---
title: "Content grid with breakouts"
description: "Use it as the container of every page, whether or not anything on it goes wider than the content."
canonical: https://good-css.com/content-grid-with-breakouts.md
last-updated: 2026-11-05
---

# 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.

The container defines three nested widths with named grid lines:

```css
.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:

```css
: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:

- Two lines named `content-start` and `content-end` create a named area, `content`. That is why `grid-column: content` works 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: inherit` gives 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-width` wrapper with the grid, and keep the wrapper's width as `--content` on 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`.

- Borrowed from: Kevin Powell, [A new approach to container and wrapper classes](https://www.youtube.com/watch?v=c13gpBrnGEw), 2023-11-09 · Ryan Mulligan, [Layout Breakouts with CSS Grid](https://ryanmulligan.dev/blog/layout-breakouts/) · Stephanie Eckles, [SmolCSS breakout grid](https://smolcss.dev/#smol-breakout-grid)
- Docs: [MDN: named grid lines](https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Grid_layout/Named_grid_lines) · [MDN: min()](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/min)
