Skip to content

PRIMITIVE

Spread

Lay your columns down once, then let each child pick the one it wants — reading measure, one rung wider, or edge to edge. It is shell turned inside out, and both are right.

This layout is Kevin Powell's, from his content-grid pen. He teaches CSS on YouTube and it is worth your time — a great deal of what this system knows about layout was learned there. What follows is the port: the measures come from this library's own tokens, and the two traps at the foot of the page are ones the adaptation ran into rather than his.

The rungs, one flow

Nothing gets wrapped, closed or reopened. Every block here is a sibling of the one above it.

Ordinary prose sits on the reading column. Nothing is wrapped and nothing is closed and reopened — every block below is a sibling of this one.

WIDE One rung out, and level with a shell.

Back to the reading column, with no wrapper to close.

This band reaches both edges. Its own children come back to the reading column, because a full-width child lays the same tracks down again.

And the flow carries on.

HTML
<div class="spread" style="--spread-measure: 34ch; --spread-wide: 62ch">
  <p class="prose">
    Ordinary prose sits on the reading column. Nothing is wrapped and nothing is
    closed and reopened — every block below is a sibling of this one.
  </p>

  <div class="spread-wide rule-stack">
    <div class="rule-row rule-row-spec">
      <span class="rule-row-key">WIDE</span>
      <span class="rule-row-value">One rung out, and level with a shell.</span>
    </div>
  </div>

  <p class="prose">Back to the reading column, with no wrapper to close.</p>

  <section class="spread-full" style="background: var(--ds-sunk); padding-block: var(--ds-pad-band)">
    <p class="prose">
      This band reaches both edges. Its own children come back to the reading
      column, because a full-width child lays the same tracks down again.
    </p>
  </section>

  <p class="prose">And the flow carries on.</p>
</div>

A band lays the same tracks again

The children of a full-width band come back to the reading column — and the band never learns a single measure to do it.

A child of the band, on the reading column.

WIDE And a wide one, inside the same band.
HTML
<div class="spread" style="--spread-measure: 34ch; --spread-wide: 62ch">
  <section class="spread-full" style="background: var(--ds-sunk); padding-block: var(--ds-pad-band)">
    <p class="prose">A child of the band, on the reading column.</p>
    <div class="spread-wide rule-stack">
      <div class="rule-row rule-row-spec">
        <span class="rule-row-key">WIDE</span>
        <span class="rule-row-value">And a wide one, inside the same band.</span>
      </div>
    </div>
  </section>
</div>

Which one to reach for

Shell is a box with a measure. To break out of it you close it, put a band beside it, and open another one — which is exact, obvious in the markup, and means every full-width thing cuts the page in half.

<section class="shell shell-section">…prose…</section>

<div class="shell-flush bg-sunk">          <!-- close, band, reopen -->
  <div class="shell shell-band">…the interruption…</div>
</div>

<section class="shell shell-section">…prose…</section>

A spread turns that inside out. The columns exist once and a child names the one it wants, so a page of prose with three interruptions in it is still one list of siblings — which is the shape a Markdown renderer hands you, and the shape you cannot wrap after the fact.

<main class="spread">
  <p>…prose…</p>
  <section class="spread-full">…the interruption…</section>   <!-- a sibling -->
  <p>…prose…</p>
</main>

Reach for a shell when the bands are the structure — a landing page of set-pieces. Reach for a spread when the page is mostly one flow and a band is an interruption in it — an article, a case study, a page of documentation.

Reference

Read from primitives/spread.css when this page was built, so it cannot fall behind the stylesheet.

CLASSES.spread.spread-wide.spread-full
SETTINGSSet the first on one element; a theme sets the second for all of them.--spread-wide — falls back to --ds-shell-max--spread-measure — falls back to --ds-measure--flow — falls back to --ds-flow--spread-gutter — falls back to --ds-pad-shell
READSNothing from the theme — it is arrangement only.

Notes

THE RUNGS ARE THE MEASURES THE REST OF THE SYSTEM ALREADY USES

The reading column is --ds-measure and the wide rung is --ds-shell-max — the same value a .shell uses for its own width. So a .spread-wide child and a shell further up the page line up to the pixel, and a site can hold both systems without the seam showing.

IT LAYS OUT AND PAINTS NOTHING

A full-width band with no background is invisible — the colour is yours, from a role, which is why the specimens above set it inline rather than the primitive carrying a paint modifier. A primitive that painted would be two decisions in one class, and the reason this one can be dropped into any theme is that it holds none of them.

THE GUTTER IS A TRACK, NOT PADDING

Padding on the grid would sit inside the full-width column too, so an edge-to-edge band would stop short of the edge by exactly the gutter. As outer tracks the gutters hold the reading column in from the window and the band still reaches it.

A CHILD OF A CHILD IS NOT A CHILD

Only direct children sit on these columns, which is why a band re-declares the template with grid-template-columns: inherit. It takes whatever the spread above it resolved to without naming a single measure of its own, so a band nested three deep still agrees with the page.

THE WIDE RUNG CANNOT GO NEGATIVE, AND THAT TOOK AN EDIT

Its width is half the difference between the two measures, and the reading measure is in ch — so a large minimum font size, or a wide display face, can make the reading column the wider of the two. A negative track is not a track: the whole declaration is dropped and the page loses its layout rather than its breakout. The wider rung is taken as at least the reading measure before the subtraction, so the worst case is a spread whose wide rung simply equals its reading column.