Arrangements
Stack, cluster, split and center: the four moves most layouts are made of.
On this page
Most layouts are a few moves repeated: stack things, let them wrap, push two groups apart, center one. Each is two or three utilities. None of them is a class in Master UI, on purpose: a class would only rename the utilities, and the next variation would need another class.
This page is the vocabulary. The other layouts, the blocks and the pages are sentences written in it.
#Stack
A stack puts things in a column at one distance: flex flex-col and a gap. The gap belongs to the stack, not to its children, so adding or removing a child never leaves a stray margin.
Stack
<div class="flex flex-col gap-md w-full max-w(320)"> <div class="well p-md">One</div> <div class="well p-md">Two</div> <div class="well p-md">Three</div></div>Use the spacing scale for the gap: gap-xs (8px) between a label and its value, gap-md (16px) between fields, gap-xl (32px) between sections.
#Cluster
A cluster is a row that wraps: flex flex-wrap and a gap. Use it for things of different widths that belong together, such as tags, filters or a group of buttons. The gap applies between lines too.
Cluster
<div class="flex flex-wrap gap-xs max-w(360)"> <span class="chip">Design</span> <span class="chip">Engineering</span> <span class="chip">Research</span> <span class="chip">Operations</span> <span class="chip">Support</span> <span class="chip">Legal</span> <span class="chip">Finance</span></div>#Split
A split pushes two groups to opposite ends of a row: flex items-center justify-between. With flex-wrap and a gap the second group drops under the first when they no longer fit, instead of squeezing it.
Split
<header class="sheet flex flex-wrap items-center justify-between gap-sm w-full max-w(520) p-md"> <div class="flex flex-col gap-3xs"> <h3 class="heading heading-sm">Members</h3> <p class="m(0) text-sm fg-text-muted">Four people have access.</p> </div> <div class="flex gap-xs"> <button type="button" class="btn btn-sm">Export</button> <button type="button" class="btn btn-sm btn-primary">Invite</button> </div></header>To push only the last item, give it ml-auto and leave the rest where they are.
Pushed to the end
<div class="sheet flex items-center gap-sm w-full max-w(520) p-sm"> <button type="button" class="btn btn-quiet btn-sm">Bold</button> <button type="button" class="btn btn-quiet btn-sm">Italic</button> <button type="button" class="btn btn-quiet btn-sm">Link</button> <button type="button" class="btn btn-sm btn-primary ml-auto">Publish</button></div>#Center
To center one thing in a box on both axes: flex items-center justify-center on the box. To center a column on the page and stop it growing: a maximum width and mx-auto on the column.
Center
<div class="well flex items-center justify-center w-full h(200)"> <button type="button" class="btn">In the middle</button></div>A measure
<article class="max-w(480) mx-auto text-sm leading-md fg-text-body"> <h3 class="heading">A column that stops</h3> <p class="mt-xs m(0)">A measure is a maximum width with automatic margins. The column fills a phone and stops growing when the lines are long enough to read, about 45 to 75 characters. Nothing else is needed to center it.</p></article>#Columns
grid grid-cols(3) makes three equal columns that share the width, and grid-col-span(2) lets one item take two. For a number of columns that follows the width by itself, use an auto grid; for tiles of a few sizes, a bento; for tiles of their own heights, masonry.
Columns
<div class="grid grid-cols(3) gap-md w-full"> <div class="well p-md">One</div> <div class="well p-md">Two</div> <div class="well p-md">Three</div> <div class="well p-md grid-col-span(2)">Four, across two</div> <div class="well p-md">Five</div></div>#Beside
Two things side by side, one of a fixed width and one that takes the rest, that stack when the rest would be too narrow, need no query either. Put flex flex-wrap and a gap on the pair; give the narrow one grow(1) basis(…), its width when they share a row; give the wide one grow(999) basis(0) and a min-w(…). The wide one takes nearly all the room there is, and when that room falls under its minimum the row wraps, and the narrow one stretches across the row above it.
Beside
<section class="flex flex-wrap gap-lg p-lg bg-surface-base fg-text-body text-sm"> <aside class="sheet flex flex-col gap-xs grow(1) basis(240) p-md" aria-label="Filters"> <h3 class="heading heading-sm">Filters</h3> <label class="flex items-center gap-xs"> <input type="checkbox" class="checkbox" checked>Open</label> <label class="flex items-center gap-xs"> <input type="checkbox" class="checkbox">Assigned to me</label> </aside> <div class="sheet flex flex-col gap-xs grow(999) basis(0) min-w(320) p-md"> <h3 class="heading heading-sm">Issues</h3> <p class="m(0) leading-md">The list takes everything the filters leave. Under 320px of its own it would be too narrow to read, so the row wraps instead.</p> </div></section>#Responding to the room
A variant changes a utility at a width. @md and its family measure the viewport: use them for the frame of the page. @container(--2xl) and its family measure the nearest size container, which is any ancestor with container-inline: use them for everything inside the frame, so a piece behaves the same in a wide page, a sidebar and a dialog.
Responsive
<section class="container-inline p-lg bg-surface-base fg-text-body text-sm"> <div class="flex flex-col flex-row@container(--2xl) gap-md"> <div class="sheet p-lg grow(1) basis(0)"> <h3 class="heading heading-sm">Stacked when narrow</h3> <p class="m(0) mt-xs leading-md">This is a stack until its container is 42rem wide.</p> </div> <div class="sheet p-lg grow(1) basis(0)"> <h3 class="heading heading-sm">Side by side when wide</h3> <p class="m(0) mt-xs leading-md">Then the same markup is a row of equal columns.</p> </div> <div class="sheet p-lg grow(1) basis(0)"> <h3 class="heading heading-sm">By its own width</h3> <p class="m(0) mt-xs leading-md">The query measures the section, not the screen.</p> </div> </div></section>| Variant | Measures | Use it for |
|---|---|---|
@xs @sm @md @lg | The viewport: 48, 52.125, 64, 80rem | The frame of a page |
@container(--md) … @container(--5xl) | The nearest container: 28 … 64rem | A region inside a page |
@container(--max-3xl) | The same, below the width | The narrow case |
#When a class is right
A few things cannot be written with utilities, or are easy to get wrong each time: a height in dvh, the inset for a phone's home indicator, a sticky column with its own scroll, a grid that counts its own columns, tiles that span cells only while there are cells to span, lanes that pack, a column that a figure steps out of, panels that stick one under another. Those are the layout classes:
| Class | What utilities cannot write |
|---|---|
auto-grid | A track list that counts its own columns |
bento | Columns that follow the room, spans that follow the columns, rows with a floor |
masonry | Grid lanes, and a multi-column box where there are none |
breakout | A column at a measure, and margins measured in the room around it |
sticky-stack | Offsets counted from each panel's place among its siblings |
form | Container thresholds, and actions whose order reverses |
page, shell | The frames of a whole page: dvh, the safe area, sticky columns |
Everything else is on this page.
#Accessibility
- Order in the source is the order for the keyboard and for a screen reader.
flex-row-reverseandorder(…)change what is seen, not what is read: use them only where both orders make sense. - A layout utility adds no meaning. Use the element that says what the thing is,
<nav>,<header>,<ul>, and put the utilities on it.
#Related
- Auto gridAs many equal columns as fit, counted by the grid itself.
- BentoTiles of a few sizes fitted into one box, in columns that follow its room.
- MasonryTiles of their own heights, packed into lanes with no gaps under them.
- BreakoutA reading column that a figure or a band can step out of, wider or to the edges.
- Sticky stackPanels that pile up under one another as the page scrolls.
- FormThe rhythm of a form: rows, sections and actions that follow their column.