Layout reference
Each pattern is a class that declares intent. Its data attributes choose a configuration, and the values come from tokens. An attribute value that is not listed here does nothing.
.stack
Section titled “.stack”Stack - Vertical rhythm.
.stack { display: flex; flex-direction: column; gap: var(--stack-gap, var(--space-4)); }| Attribute | Values | Sets |
|---|---|---|
data-gap |
0 1 2 3 4 5 6 7 8 10 12 tight normal loose |
--stack-gap |
data-align |
start center end stretch |
align-items |
data-justify |
start center end between |
justify-content |
.cluster
Section titled “.cluster”Cluster - Horizontal grouping with wrapping.
.cluster { display: flex; flex-wrap: wrap; gap: var(--cluster-gap, var(--space-3)); align-items: var(--cluster-align, center); }| Attribute | Values | Sets |
|---|---|---|
data-gap |
0 1 2 3 4 5 6 8 tight normal loose |
--cluster-gap |
data-align |
start center end baseline stretch |
--cluster-align |
data-justify |
start center end between around |
justify-content |
Grid - Responsive cards with minimum width.
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(var(--grid-min, 280px), 100%), 1fr)); gap: var(--grid-gap, var(--space-5)); }| Attribute | Values | Sets |
|---|---|---|
data-min |
200 240 280 320 360 400 |
--grid-min |
data-gap |
2 3 4 5 6 8 10 |
--grid-gap |
data-align |
start center end stretch |
align-items |
.sidebar
Section titled “.sidebar”Sidebar - Fixed sidebar + flexible main.
.sidebar { display: flex; flex-wrap: wrap; gap: var(--sidebar-gap, var(--space-6)); }.sidebar > :first-child { flex-basis: var(--sidebar-width, 16rem); flex-grow: 0; flex-shrink: 0; }.sidebar > :last-child { flex-basis: 0; flex-grow: 999; min-inline-size: 50%; }| Attribute | Values | Sets |
|---|---|---|
data-side |
end |
> |
data-sidebar-width |
12 14 16 18 20 24 |
--sidebar-width |
data-gap |
4 5 6 8 10 |
--sidebar-gap |
.center
Section titled “.center”Center - Constrain width, keep things readable.
.center { box-sizing: content-box; margin-inline: auto; max-inline-size: var(--center-max, 70ch); padding-inline: var(--center-padding, var(--space-6)); }| Attribute | Values | Sets |
|---|---|---|
data-max |
50 60 70 80 90 40rem 48rem 56rem 64rem 80rem |
--center-max |
data-padding |
4 6 8 0 |
--center-padding |
data-text |
center |
text-align |
.switcher
Section titled “.switcher”Switcher - side by side while every part has room, stacked when not. The threshold is the pattern’s own inline size at which the parts stop fitting; no media or container query is involved, so it responds to whatever space it is given, not to the viewport..
.switcher { display: flex; flex-wrap: wrap; gap: var(--switcher-gap, var(--space-6)); align-items: var(--switcher-align, stretch); }.switcher > * { flex-grow: 1; flex-basis: calc((var(--switcher-threshold, 40rem) - 100%) * 999); min-inline-size: 0; }| Attribute | Values | Sets |
|---|---|---|
data-threshold |
30 36 40 44 48 52 56 |
--switcher-threshold |
data-ratio |
4:3 3:2 2:1 3:4 2:3 1:2 |
> |
data-gap |
4 6 8 12 loose |
--switcher-gap |
data-align |
start center end |
--switcher-align |