// css · Web Platform Advent #16
CSS Subgrid: make nested grids share the parent's lines
A nested grid invents its own tracks, so sibling cards never line up. Subgrid makes a child adopt its parent's track lines - what it fixes, the two rules to remember, and how it differs from display: contents.
Subgrid solves one specific frustration, and it is worth stating precisely because everything else follows from it: a nested grid creates its own tracks, which have nothing to do with the parent's. So three cards in a row, each laying out its title, body and footer as an internal grid, will each size those rows independently - and the footers will not line up.
Subgrid tells a child to stop inventing tracks and use the parent's lines instead.
The problem, concretely
Here is the layout everybody hits. An outer grid of cards, and each card is itself a grid of three rows:
.cards {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
}
.card {
display: grid;
grid-template-rows: auto 1fr auto;
} Each card now sizes its own three rows from its own content. A card with a two-line title gets a taller first row than its neighbour with a one-line title. The result is three cards whose internal elements are all slightly out of step - and no amount of styling inside the card can fix it, because each card is measuring in isolation.
The fix, and the two rules
Make the card a subgrid on the axis you want aligned:
.cards {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: auto 1fr auto;
gap: 1rem;
}
.card {
display: grid;
grid-row: span 3;
grid-template-rows: subgrid;
} Now every card's three rows are the parent's three rows. The tallest title in the set defines row 1 for all of them, so every title, body and footer sits on the same line across the row.
Two rules are worth committing to memory, because almost every "subgrid is not working" question comes down to one of them:
- The element must be a grid item of the grid it is subgridding. Subgrid is not inherited across a wrapper - put a plain
<div>between the parent grid and the card and the relationship is broken. - It only adopts the tracks it spans. A card spanning three rows adopts three rows. If you do not declare the span, it spans one, and you get one track - which looks exactly like subgrid doing nothing.
It works per axis
You subgrid rows and columns independently. A child can take the parent's columns while defining its own rows, which is common:
.child {
display: grid;
grid-column: span 4;
grid-template-columns: subgrid; /* parent's columns */
grid-template-rows: auto auto; /* its own rows */
} That combination is how you align a nested block to a page-wide column system without giving up control of its vertical rhythm.
Gaps and named lines come along
Two conveniences that are easy to miss:
- Gap is inherited from the parent on the subgridded axis, which is usually what you want. Set
gapon the child to override it. - Named grid lines are inherited too, so if the parent defines
[content-start]and[content-end], the child can place items against those names directly.
Subgrid versus display: contents
Before subgrid, the usual workaround was display: contents on the wrapper, which removes its box and promotes its children to grid items of the outer grid. It aligns things, and it costs you the box: no background, no border, no padding, no border-radius on the card, because the card no longer generates a box to paint them on.
display: contents | subgrid | |
|---|---|---|
| Alignment across siblings | Yes | Yes |
| Keeps the wrapper's box | No | Yes |
| Background, border, padding | Lost | Kept |
| Per-axis control | No | Yes |
If you need the card to look like a card, subgrid is the answer and display: contents never was.
Browser support
Firefox shipped subgrid first, back in 2019, and spent several years as the only engine with it. Safari added it in 2022 and Chrome in 2023, so it is available across current versions of all major browsers - which is recent enough that it is worth checking your own support target rather than assuming.
The mental model is simple once it clicks: a normal nested grid asks "how much room do I have, and how shall I divide it?" A subgrid asks "where are my parent's lines?" - and that second question is the one that makes rows of cards look designed rather than merely arranged. If you are still choosing between layout mechanisms in the first place, start with CSS Grid vs Flexbox; and for components that must adapt to the space they are given rather than to the screen, pair this with container queries.