# Content columns

> A long-form editorial section held to a strict reading measure, with a narrow sidenote rail hanging outside it: each note sits under its own hairline beside the paragraph it annotates, and drops beneath that paragraph on a phone. States no colour and no font of its own.

Canonical: https://patternpaste.com/pattern/content-columns.html
Section: Editorial
Access: Included in Pattern Paste access.
Needs: Requires a block theme on WordPress 7.0 to 7.1. Classic themes and page builders are outside our supported setup. Adaptive patterns use the block theme’s colour, spacing and typography presets; styled variations declare their own colours or type.
Blocks: column, columns, group, heading, paragraph, separator
Keywords: editorial, article, long-form, sidenote, marginalia, measure, columns

Promise: Identical markup in every theme.

---

## The signature moment: hanging marginalia

The body copy never widens. It is set at a fixed 33rem measure and stops there
however wide the section gets, and the space that opens up to the right of it is
not padding: it is a rail, 15rem across, where each note hangs beneath its own
hairline **level with the top of the paragraph it annotates**. The rules march
down the right-hand side of the article like ticks on a ruler, so a reader can
see at a glance which paragraphs carry a note and which do not, without a single
marker interrupting the sentences themselves.

The scale does the rest. Body copy runs 17 to 20px on a 1.75 line height; the
notes are 15 to 16px on 1.55, each introduced by a 13px uppercase index tracked
at 0.18em; the eyebrow and the byline that frame the section are 14px at the
same weight. Four sizes and one rule per note is the whole vocabulary, which is
what makes it survive a theme that supplies neither colour nor typeface.

## How the notes align beside their paragraphs, with no CSS to do it with

**Each movement is its own `core/columns` row.** That is the entire mechanism,
and it is the reason the pattern is four rows rather than one two-column layout
with all the copy on the left and all the notes on the right.

A columns row lays its children out from a shared top edge, so the note column's
first block starts at exactly the same y as the text column's first block. Put
one annotated passage in the text column and its note in the note column, and
alignment is structural rather than something a stylesheet has to arrange. The
note's hairline is the first block in the rail column, so it lands on the top
edge of the paragraph's first line box: a rule tucked against the ascenders,
which is what makes the note read as attached to that paragraph rather than as
the start of a parallel column.

The single-row alternative was rejected on purpose. One row containing four
paragraphs and four notes would align only the first pair, drift further apart
with every paragraph whose length differs from its note, and, worse, would put
every note at the bottom of the article the moment the row stacked. Binding one
note to one row costs nothing and makes both problems impossible.

## The measure, and why it cannot run away

**The reading measure is `flex-basis: 33rem` on the text column, and the section
contains no `vw` width anywhere.** The band's own `contentSize` is `50.5rem`,
which is exactly `33rem` of text plus a `2.5rem` gutter plus `15rem` of rail, so
the spread fills its container at the width it was drawn for and shrinks
proportionally below it.

Why that is safe in a theme nobody has measured: characters per line is column
width divided by glyph advance, and glyph advance scales with font size. Every
width in this pattern is in `rem` and every font size is a `clamp()` whose floor
and ceiling are in `rem`, so a theme or a user that changes the root size scales
the column and the letters in the same proportion and the character count does
not move. A width in `vw` breaks precisely that link: the column follows the
viewport, the type does not, and the measure drifts every time the window
changes. That is the defect that cost `faq-list` a round, and it is the one thing
in this file that is not a taste question.

The numbers, for the widest case. At 1280 the text column is 528px and the body
lands at 18.6px, which is 55 to 60 characters in the faces these themes ship. The
worst case the arithmetic allows is the body clamp at its 17px floor in a
condensed face with a 6px average advance, and 528 divided by 6 is 88: still
inside the 95-character limit, in a theme with a face nothing here has seen. The
intro lede and the heading live in the full 50.5rem band rather than in the
column, and each sits in its own nested `core/group` with a constrained layout
(`contentSize` 33rem for the lede, 42rem for the heading) and `justifyContent:
left`, so they are capped at those widths, pinned to the band's left edge, and
line up with the body below.

**An earlier version used `padding-right: max(0rem, 100% - 33rem)` on the
block itself, and that was a defect.** The padding resolves correctly, but a
paragraph is `content-box`, so the padding sits outside the layout's
`max-width`: the block grew to the band's full width and the layout's centring
put its left edge at the band's padding edge, 246px left of the body column at
1400. Measured on the rendered preview: heading and lede at `left: 50px, width:
1300px`, the body at `left: 296px`. The width was right, so nothing flagged
it. The trick is still sound inside a column, where nothing centres the block;
`faq-list` uses it that way.

## What happens at 390

Below 782px core forces every `.wp-block-column` to `flex-basis: 100%
!important` at 0-3-0, which nothing a pattern can emit will beat, so the rows
stack. **That is the intended behaviour here and the pattern is authored for
it:** `isStackedOnMobile` is deliberately left at its default rather than turned
off, because a 15rem rail sitting beside a 33rem column inside a 342px phone
screen would be two ribbons of three words each.

What a hanging note becomes when there is no margin to hang in: **an interleaved
note, still ruled, still smaller, still attached.** Because each note lives in
the same row as the passage it annotates, stacking puts it immediately beneath
that passage and immediately above the next one. It keeps its hairline, which now
runs the full width of the phone and reads as a break in the flow of the article;
it keeps its uppercase index, which is what tells a reader this is an aside
rather than the next paragraph; and it keeps its smaller size, since every size
here is a `clamp()` with a `rem` floor rather than a percentage of anything.

The mobile answer is therefore not a fallback. It is the same relationship drawn
with the only geometry a phone has, and the reason it works is the same reason
the desktop alignment works: the note is bound to a paragraph, not to the
article.

There are no links and no buttons in this section, so there is no tap target to
clear 44px. That is a design decision as much as a convenience: an editorial
section that ends in a call to action is a landing page, and a page built from
this catalogue already has `cta-band` for that.

## What it inherits from your theme

- **Typeface.** No font family is stated anywhere. The heading, the body, the
  notes and the indices all take whatever your theme sets, and the pattern was
  drawn to hold its proportions in a serif face and a sans one.
- **Palette.** The ground is your `base` and the text is your `contrast`, each
  written as a two-rung fallback chain ending on a colour WordPress itself
  guarantees (`base` to `white`, `contrast` to `black`), so the section paints in
  a theme with a full palette and still paints in a theme with none.
- **Every rule in the section.** The five hairlines, the four in the rail and the
  two closing the article, are `core/separator` blocks stating no colour at all,
  so they take your theme's separator style and cannot blank: `currentColor` in
  Twenty Twenty-Four and Twenty Twenty-Five, and a 2px `currentColor` rule in a
  theme that styles nothing.
- **Spacing rhythm.** Section padding, the space between movements, the space
  between paragraphs and the space under each hairline are core spacing presets,
  so the article breathes at your scale rather than ours.

## What it decides for itself

- **The measure**, at 33rem, and the rail, at 15rem, both in `rem` and never in
  `vw`. This is the pattern. Widen the measure and the rail stops hanging outside
  anything; drop the rail and this is a column of text.
- **The gutter**, at 2.5rem. It has to be wide enough that the note reads as
  outside the measure rather than as a second column of the same article.
- **Proportion.** Body at `clamp(1.0625rem, 1.45vw, 1.25rem)` on 1.75; notes at
  `clamp(max(0.9375rem, 15px), 1.05vw, 1rem)` on 1.55; lede at `clamp(1.125rem,
  1.7vw, 1.375rem)` on 1.55; heading at `clamp(1.875rem, 4.2vw, 3.125rem)` on
  1.05 with -0.025em tracking. The `vw` terms size type, which is what `vw` is
  good at; none of them sizes a box.
- **A px guard under every small size.** The eyebrow and the byline are
  `max(0.875rem, 14px)` and the note indices are `max(0.8125rem, 13px)`, so a
  theme that shrinks the root font size cannot push fine print under the floor
  where it stops being readable on a phone. The `rem` term still leads, so a
  theme that grows the root still scales them; the `px` term only ever stops a
  fall. Measured: at a flat 13px the byline fell under the 14px body floor at
  390 in all four themes, because at 37 characters it counts as copy to be read
  rather than as an incidental label.
- **The note index.** A tiny uppercase `Note 01` rather than a superscript
  marker, because a superscript needs a link to be worth anything and this
  pattern carries no interactivity.

## What you change first

1. **The copy.** Four movements of one or two paragraphs each, four notes. The
   article is about reading measure because that is what the pattern is for;
   replace all of it.
2. **The count.** A movement is one `core/columns` row. Copy a whole row to add
   one, delete a whole row to remove one, and keep the note column populated:
   an empty column is not an empty rail, it is an invalid block.
3. **A paragraph with nothing to annotate.** Put it in the text column of the row
   above or below rather than making a row for it, or the rail grows a gap where
   a rule should be.
4. **The note length.** Keep a note to two sentences. The rail is 15rem, roughly
   33 characters a line, so a long note runs down past its paragraph and the
   alignment that makes the device work stops being visible.
5. **The byline.** The closing line is a placeholder set at the same size as the
   eyebrow that opens the section; they are a matched pair, so change both or
   neither. Keep it at or above 14px whatever you write there: the moment a line
   runs past about thirty characters it stops being a label and becomes
   something a visitor is expected to read.

## Contrast

Every pair in the section is your `contrast` on your `base`, which is the pair
your theme already ships body copy on. The heading carries that colour
explicitly rather than inheriting it, because a theme's heading element style
beats an inherited group colour and that is how a headline ends up invisible.
The heading is large text and clears 3:1; the lede, the body, the notes, the
indices and the byline are all body text and are held to 4.5:1. The hairlines
are structural marks in `currentColor` and carry no text of their own. No accent
slug appears in any rung anywhere in the file.
