Entry 01
Content grid with breakouts
Use it as the container of every page, whether or not anything on it goes wider than the content. A centered max-width wrapper is the sign, such as .container, .wrapper or Tailwind's mx-auto max-w-*. One grid on the section replaces the section > .container wrapper pair and costs no more than it, and any child can be content width, wider, or edge to edge. Put it on main for a page of flowing content, or on each section. A band, a figure or a block that an editor later wants wider then takes one class, with no negative margin and no new wrapper.
Code
The container defines three nested widths with named grid lines:
.content-grid {
--gutter: 1.5rem;
--content: 64rem;
--breakout: 80rem;
display: grid;
grid-template-columns:
[full-width-start] minmax(var(--gutter), 1fr)
[breakout-start] minmax(0, calc((var(--breakout) - var(--content)) / 2))
[content-start] min(100% - var(--gutter) * 2, var(--content)) [content-end]
minmax(0, calc((var(--breakout) - var(--content)) / 2)) [breakout-end]
minmax(var(--gutter), 1fr) [full-width-end];
}Each child picks a width with grid-column. Content is the default:
:is(.content-grid, .full-width) > * { grid-column: content; }
:is(.content-grid, .full-width) > .breakout { grid-column: breakout; }
:is(.content-grid, .full-width) > .full-width {
grid-column: full-width;
display: grid;
grid-template-columns: inherit;
}Why it works, the rules and the credits
Why it works
- Two lines named
content-startandcontent-endcreate a named area,content. That is whygrid-column: contentworks with no line numbers. min(100% - 2 × gutter, max)shrinks the content column on small screens with no media query.minmax(0, …)lets the breakout tracks collapse, so a breakout falls back to content width when there is no room. With a fixed breakout size the page overflows on small screens.grid-template-columns: inheritgives a full-width band the same grid, so content inside it lines up with the page column without another wrapper. This is Kevin Powell's addition. In Ryan Mulligan's original the full-width child is a plain box.
Rules
- Every child must be placed. An unplaced child of the grid lands in the gutter track.
- Every direct child is a grid item. Wrap a run of inline elements in one element.
- Change a width by overriding
--content, not by writing a new column template. - In a pass over existing CSS, replace each centered
max-widthwrapper with the grid, and keep the wrapper's width as--contenton its section.
In other systems
The column template goes wherever the project defines reusable styles. Where child selectors are not available, as in StyleX or Tailwind without a custom variant, each child sets its own grid-column to content, breakout or full-width.
Credits
Borrowed from: Kevin Powell, A new approach to container and wrapper classes, 2023-11-09 · Ryan Mulligan, Layout Breakouts with CSS Grid · Stephanie Eckles, SmolCSS breakout grid
Docs: MDN: named grid lines · MDN: min()