Layout · container primitive
A pattern from the gf.cx specimen book
The plate that outgrows its column
Prose wants a narrow measure. A chart, a wide table, a map does not — it wants every pixel the page will give it. The fix is one line on the child, but only if the container has told it how much padding there is to cancel.
"edge to edge - full width" … "920px"
The problem
A centred column is two numbers: a max-width and a side
padding. Content sits inside both. When one block needs to escape
the padding, the reflex is a negative margin with the padding value typed in
again:
.page { max-width: 920px; padding: 2rem 1.5rem 4rem; }
.chart { margin-inline: -1.5rem; } /* ← the same number, twice */
That works until the day it doesn't, and it fails silently. Change the container's padding and the child keeps cancelling the old value — now it either leaves a sliver of gutter or hangs over the edge. Worse, the container usually already changes its own padding somewhere you weren't looking. On the gf.cx vehicle pages it is the print stylesheet:
@media print { .page { max-width: none; padding: 0; } }
With a hard-coded -1.5rem, printing the page pulls the plot
24px off the left edge of the sheet — cropped by the printer, discovered by
whoever printed it.
The pattern
Make the padding a value the container publishes, and have the child cancel that rather than a copy of it:
.page { --page-pad: 1.5rem;
max-width: 920px; margin: 0 auto;
padding: 2rem var(--page-pad) 4rem; }
.bleed { margin-inline: calc(-1 * var(--page-pad, 0px)); }
@media print { .page { --page-pad: 0px; max-width: none; padding: 0; } }
Now there is one number. The child inherits it through the cascade, so it
tracks every override automatically — including the print rule, where the bleed
collapses to zero because there is no padding left to cancel. The
0px fallback is the other half: drop the same child into a page
that never declared --page-pad and it simply doesn't bleed, rather
than jumping sideways by a value it guessed.
What it looks like
This page publishes --page-pad on its own main,
so the specimen below is the real thing, not a picture of it. The dashed box
holds the text measure; the white plate escapes it by exactly the page padding
and spans the container's full 920px box:
On a narrow viewport the max-width never binds, so the same
rule resolves to genuine viewport edge-to-edge with no media query and no
second code path.
Why not 100vw
The usual full-bleed recipe is width: 100vw; margin-inline: calc(50%
- 50vw). It breaks out of any ancestor, which sounds stronger
and is usually worse:
- It ignores the container. On a page whose column is
centred in a wider tinted card,
100vwblows through the card too — the block loses the frame it belonged to. - It counts the scrollbar.
100vwincludes the classic scrollbar gutter on Windows and GTK, so the page gains a horizontal scrollbar that no one sees on macOS overlay scrollbars — a bug that ships because the author's machine can't show it. - It has nothing to say about print, where the viewport is a sheet of paper.
Cancelling the padding is the smaller claim and the more accurate one: as wide as my container, not as wide as the screen.
Where it applies
- Any single block wider than its prose — SVG charts, wide data tables, image strips, maps, code samples that shouldn't wrap.
- Generated surfaces especially. The generator emits
<div class="bleed">and the page's stylesheet owns the number. Neither side has to know the other's value, so a re-render can't revert the layout and a restyle can't strand the generator. - Skip when the block should genuinely escape every
ancestor to the viewport edge — a hero image or a colour band. That is the
100vwcase, and it should be written as one.
Reusable elements
- The published-padding custom property —
--page-paddeclared on the container and consumed in its ownpaddingshorthand, so the declaration and the use can never disagree. - The cancelling child —
margin-inline: calc(-1 * var(--page-pad, 0px)). One declaration, no media queries, degrades to a no-op. - The print collapse — set
--page-pad: 0pxalongsidepadding: 0in the print block and every bleeding child on the page follows in one line.
Reference
- Origin
- home.gf.cx vehicle pages, 2026-08-11 — the mileage-timeline closing plate, which had to reach the full 920px box while its heading and captions stayed on the text measure.
- Reference impl
~/bin/pa_vehicle_mileage_chart_inject.pyemits<div class="chart-bleed">; the page stylesheet owns--page-pad. Live at home.gf.cx/vehicles/LR4.- Failure it prevents
- A hard-coded negative margin surviving a container-padding change — silently on screen, visibly on paper, where
@media printzeroes the padding and the block runs off the sheet. - Related patterns
- Built-with provenance footer — the same one-source-of-truth model applied to page provenance.
- Build cost
- Two CSS declarations and one wrapper element. No shared asset, no script, nothing to load.