CSS

The reset, the layout, the utilities and the theme tokens: the foundations of every iRoom page.

Foundations

The reset

The first layer of the cascade. It removes the differences between the browsers and the defaults that get in the way, without styling anything.

RuleWhy
box-sizing: border-box everywherea width includes the padding and the border
no margin on the body, the titles, the paragraphs, the liststhe base layer sets the rhythm, not the browser
text-size-adjust: 100%no font inflation when a phone turns to landscape
min-height: 100dvh on the bodythe page fills the screen, mobile toolbars included
images, videos and svg in block, max-width: 100%no gap under the images, never wider than their parent
fields: font: inherit, color: inheritthe fields use the font of the page
overflow-wrap: break-word on the textsa long url never makes the page scroll sideways
ul[role="list"] without bulletsSafari keeps the semantics of the list
Firefox focus ring and invalid glow, Safari search fields, number arrowsthe same fields in every browser
[hidden] always hidden, but until-foundhidden means hidden, whatever the display
prefers-reduced-motion: reducethe animations become instant for those who asked

Foundations

Cascade layers

The framework is split in six layers. A later layer always wins over an earlier one, whatever the specificity; your own CSS, outside of any layer, wins over all of them.


                        @layer reset, tokens, base, layout, components, utilities;

                        /* yours, unlayered: one class is enough to override a component */
                        .btn { border-radius: 0; }
                    

Foundations

Light, dark and auto

Light by default; data-theme="dark" forces the dark theme, data-theme="auto" follows the system. On the page or on any element.

Light

data-theme="light"

Success

Dark

data-theme="dark"

Success

A data-theme-toggle button switches the theme and saves it (JavaScript). .dark-only and .light-only show a content in one theme. To avoid a flash at the load, apply the saved theme in the head:


                        <script>
                            try {
                                var theme = localStorage.getItem('iroom-theme');
                                if (theme) document.documentElement.setAttribute('data-theme', theme);
                            } catch (e) {}
                        </script>
                    

Foundations

Design tokens

Every value is a custom property prefixed with --ir-. Override them in your stylesheet, no rebuild needed.


                        :root {
                            --ir-primary: #6d3fc0;    /* and --ir-on-primary for its text */
                            --ir-radius: .75rem;
                            --ir-gutter: 1.5rem;
                            --ir-font-body: 'Inter', sans-serif;
                        }

                        /* a local change needs data-theme, to recompute the derived shades */
                        .promo[data-theme] {
                            --ir-primary: #c2255c;
                        }
                    
TokensUse
--ir-primary, -success, -warning, -danger, -infothe solid colors, with --ir-on-* for their text
--ir-*-hover, -soft, -border, -strongderived with color-mix(), never set by hand
--ir-bg, --ir-surface, -surface-2, -surface-3the backgrounds, by theme
--ir-text, -text-muted, -text-subtle, --ir-border, -border-strongthe texts and the borders, by theme
--ir-font-body, -font-heading, -font-mono, --ir-font-sizethe typography
--ir-gutter, --ir-space-*, --ir-container, --ir-navbar-heightthe spacing and the layout
--ir-radius-sm, --ir-radius, -lg, -full, --ir-shadow-*the shapes

The breakpoints, the spacing scale and the palette are Sass tokens: edit sass/abstracts/_tokens.scss and run npm run build.

Layout

Containers

Centered, with side gutters, up to a maximum width.

.container75rem (1200px)
.container-narrow48rem, for a text
.container-wide90rem
.container-fluidthe full width, no gutter

Layout

Stack, cluster and grid

Three layouts that cover most needs without a media query.

.stack: one below the other

first
second

.cluster: side by side, wrapping

flexbox layers custom properties dark mode TypeScript

.grid-auto: as many columns as possible

Each column is at least --ir-min wide: 16rem, 11rem with .grid-auto-sm, 22rem with .grid-auto-lg.

1
2
3
4
5

Layout

The grid

Twelve columns in a .row, separated by a real gap. Without a class, a column takes the full width.

Sizes

.col
.col
.col
.col-4
.col-8
.col-3
.col-3
.col-6
.col-auto
.col

Gaps and offsets

A .gap-* class changes the gap: the columns keep their size. .gap-0 glues them.

.gap-0
.col-4
.col-4
.gap-xl
.col-4
.col-4
.col-4 .offset-4

Nested rows

.col-6
.col-6
.col-4

Layout

Responsive columns

Mobile first: a suffixed class applies from its size and above. Every responsive class of the framework ends the same way.

SizeFromExamples
small0.col-6, .offset-2, .hidden
medium601px.col-6-m, .offset-2-m, .block-m
large993px.col-4-l, .col-l, .items-center-l
extra large1201px.col-3-xl, .text-left-xl

Resize the window: one column, two from the medium size, four from the large size.

.col-6-m .col-3-l
.col-6-m .col-3-l
.col-6-m .col-3-l
.col-6-m .col-3-l

Layout

Flex utilities

Every flex property, for every size: .items-center, .items-center-m, -l, -xl.

direction.flex-row, .flex-row-reverse, .flex-column, .flex-column-reverse
wrap.wrap, .nowrap, .wrap-reverse
align-items.items-start, -end, -center, -baseline, -stretch
justify-content.justify-start, -end, -center, -between, -around, -evenly
align-content.content-start, -end, -center, -stretch, -between, -around
align-self.self-start, -end, -center, -baseline, -stretch
items.flex-1, .flex-auto, .flex-none, .shrink-0, .grow-0 … .grow-12, .order-0 … .order-12, .order-first, .order-last
between
between
center
center
.flex-column
.flex-row-m
1 .order-last
2
3 .order-first

Layout

Parallax

A layer that moves slower than the page. The JavaScript gives the progress of each visible section, the CSS turns it into a translate on the compositor. The headers of this site use it.

Scroll the page:

The flex world

The image moves slower than the text, which fades as the section leaves.

.parallaxthe section: it clips the layer and gives the timeline
.parallax-layerthe moving layer: an image, a <picture>, a video or any element, behind the content
.parallax-slow, .parallax-fastthe share of the section height the layer travels: .08, .15 by default, .3
.parallax-contentoptional: rises and fades as the section leaves the screen

The JavaScript writes --parallax-progress (0 when the section enters the screen, 1 when it leaves) on the visible sections only, found by an IntersectionObserver. Without JavaScript, and for the visitors who asked for less motion, the layer stays still. For another amplitude, set --parallax and --parallax-shift, its travel in % of the layer: p / (1 + 2p).

Utilities

Display

.hidden, .block, .inline, .inline-block, .flex, .inline-flex, .grid, .contents, for every size; .invisible, .sr-only, .print-hidden, .print-only.

Resize the window:

small screen

Utilities

Spacing

Property, side, size: .padding, .margin-top-lg, .padding-x-sm, .gap-xl.

propertypadding, margin, gap
side(all), top, right, bottom, left, x, y
size0, xs .25rem, sm .625rem, (none) 1.25rem, lg 2rem, xl 3rem, xxl 5rem
auto.margin-auto, .margin-x-auto, .margin-left-auto, .margin-right-auto, .margin-top-auto
xs
sm
default
lg
xl

Utilities

Text

Alignment for every size, transforms, sizes, weights and overflow.

.text-center .text-left-m: centered on small screens

.uppercase .tracking-wide .text-sm

.weight-light .text-lg

.truncate: a very long sentence that does not fit on one line

.line-clamp-2: Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ab accusamus aperiam consectetur culpa distinctio dolorem enim eos facilis, iusto maxime minima placeat.

Utilities

Borders and shadows

They read the tokens and follow the theme.

.border .rounded-sm
.rounded
.rounded-lg
.rounded-full
.shadow-sm
.shadow
.shadow-lg
.lift

Utilities

Position and sizes

position.relative, .absolute, .fixed, .sticky (--ir-sticky-top), .inset-0, .absolute-center, .z-1, .z-10, .z-100
sizes.full-width, .full-height, .full-screen, .aspect-square, .aspect-video, .aspect-photo, .object-cover, .object-contain
overflow.overflow-hidden, .overflow-auto, .overflow-x-auto
lists.list-none, .list-inline
others.float-left, .float-right, .clearfix, .pointer, .select-none, .transition

.browser

A frame for a screenshot or a demo; with .full-screen, this block would fill the screen.