Stack layout

스택 레이아웃

A layout primitive that manages the gap between vertically stacked elements from exactly one place — proposed by Heydon Pickering and Andy Bell's Every Layout.

Also known as: Every Layout StackOwl selector spacing
···
html
<div class="frame">
  <div class="stack" id="stack" style="--space:8px">
    <div class="item">A</div>
    <div class="item">B</div>
    <div class="item">C</div>
  </div>
  <div class="tag" id="tag">--space: 8px</div>
</div>
css
.frame{display:flex;flex-direction:column;align-items:center;gap:8px}
.stack{display:flex;flex-direction:column;width:min(38vmin,200px)}
.stack > * + *{margin-block-start:var(--space)}
.item{background:var(--surface);border:1px solid var(--line);border-radius:8px;height:32px;
  display:grid;place-items:center;font-weight:800;color:var(--accent);transition:margin-block-start .6s}
.tag{font:700 clamp(9px,1.7vmin,11px)/1 ui-monospace,monospace;color:var(--accent-2);
  background:var(--surface);border:1px solid var(--line);border-radius:6px;padding:4px 8px}
js
const stack = document.getElementById('stack');
const tag = document.getElementById('tag');
const spaces = [8, 18, 30, 14];
let i = 0;
setInterval(() => {
  const s = spaces[i % spaces.length];
  stack.style.setProperty('--space', s + 'px');
  tag.textContent = '--space: ' + s + 'px';
  i++;
}, 1600);

The simplest form is display: flex; flex-direction: column with a gap. Every Layout's original technique instead uses the "adjacent sibling" combinator: .stack > * + * { margin-block-start: var(--space) }. * + * only selects elements that have a preceding sibling, so the first child gets no extra space — Heydon Pickering nicknamed it the "owl selector," after the shape it makes on the page.

The important part is exposing the gap as a single custom property, --space. Every stack across a page can set --space differently — 8px inside a small card, 32px between page sections — so you tune the "rhythm" of a whole region with one number instead of computing margins per element.

Since gap is now well supported on both flexbox and grid, the owl-selector trick itself is no longer strictly necessary — but its underlying principle still holds: the parent owns the spacing, and children don't need to know it exists. Put margin directly on a child component instead, and that margin follows the component around when it's reused somewhere else — inside a grid cell, say — where it isn't wanted.

When to use

A near-default for almost anything that stacks vertically one item at a time with uniform spacing — elements inside a card, form fields, body paragraphs.