Community CSS Snippet
The 12-Column Grid I Keep, With Named Areas and Container Queries
I rewrote our marketing site grid three times before settling on this: a 12-column CSS Grid with named areas for the hero shape, container queries for the breakpoints, and custom properties for the gutter so designers can change one value.
The 12-Column Grid I Keep, With Named Areas and Container Queries
I rewrote our marketing site grid three times before settling on this: a 12-column CSS Grid with named areas for the hero shape, container queries for the breakpoints, and custom properties for the gutter so designers can change one value.
By @lucasmoreau
January 11, 2026
·
Updated May 20, 2026
1,143 views
15
4.4 (13)
The whole layout fits on a screen because every decision is exposed as a custom property. --gutter is the single value designers ask to change, and threading it through gap, padding-inline, and any nested grid keeps everything aligned. The minmax(0, 1fr) (rather than just 1fr) is the line I always forget at first; without it, a long unbroken word in a child element forces the column wider than its share, which on a 12-column grid means columns 7-12 silently overflow the viewport. Naming columns col-span-N rather than the more recent grid-column: span var(--span) choice was deliberate: designers grep classes faster than they parse arbitrary properties.
Named areas pay off whenever the shape is non-rectangular. The headline is 8 columns wide, the subhead is 6 columns under it, and the art block sits over both rows on the right with a one-column visual break. With grid-template-areas the shape reads top-to-bottom, left-to-right exactly as it renders, and a designer reviewing a PR can spot the layout intent without running the page. The . cells are the empty columns that act as visual whitespace; they cost nothing because empty grid cells do not generate boxes. I keep the shorthand version next to it because some pages want the spans without the area names.
Container queries (@container) are the breakpoint type I have wanted for a decade. The card no longer needs to know whether it is in a sidebar or a main column; the container reports its inline size and the card responds. The two breakpoints I ship with every component are 480px (icon plus stacked text becomes icon plus inline text) and 800px (room for a CTA on the right). The @supports not (container-type: ...) block is what makes this safe to ship: Safari before 16 and Firefox before 110 fall back to a parent-class scheme that approximates the same three layouts. I have not needed the fallback in two years but I leave it because the cost is one extra @supports block.
