Subgrid
When a card sits inside a grid but its own inner rows refuse to line up with its neighbours, subgrid lets a nested grid borrow its parent’s tracks so everything aligns perfectly.
What you will learn
- Explain the alignment problem subgrid solves
- Make a nested grid inherit the parent’s tracks
- Build a row of cards whose internal rows line up
The misalignment problem
Imagine a row of cards, each with a title, a description and a button. The descriptions are different lengths, so on a normal grid each card sizes its own rows independently — and the buttons end up at different heights, looking ragged. You want every card’s title row, text row and button row to line up across the whole row, like a spreadsheet.
Subgrid solves this. A nested grid normally creates its own brand-new rows and columns. With grid-template-rows: subgrid (or grid-template-columns: subgrid), the nested grid instead borrows the parent grid’s tracks — so its rows align with every sibling’s rows.
Note: Plain-English definition: subgrid tells a child grid “do not invent your own rows/columns — reuse the ones from the grid above you”, so nested content lines up with the outer grid.
Cards whose inner rows line up
Below, three cards sit in a grid. Each card is itself a grid, and uses grid-row: span 3 plus grid-template-rows: subgrid so its title, text and button share the same three rows as the other cards. The result: titles align, texts align, and all three buttons sit at the same baseline — even though the text lengths differ. Read it, then the breakdown:
<style>
.deck {
display: grid; gap: 14px;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: auto 1fr auto; /* title / text / button rows */
}
.pcard {
display: grid;
grid-row: span 3; /* occupy all three parent rows */
grid-template-rows: subgrid; /* borrow those rows instead of making new ones */
border: 1px solid #e6e8f0; border-radius: 12px; padding: 14px; background:#fff;
}
.pcard h4 { margin: 0; color:#4338ca; }
.pcard button { background:#4338ca; color:#fff; border:none; padding:10px; border-radius:8px; }
</style>
<div class="deck">
<div class="pcard"><h4>Starter</h4><p>Short blurb.</p><button>Choose</button></div>
<div class="pcard"><h4>Pro</h4><p>A noticeably longer description that wraps onto two or three lines.</p><button>Choose</button></div>
<div class="pcard"><h4>Team</h4><p>Medium length text here.</p><button>Choose</button></div>
</div>Even though the middle card’s description is much longer, all three buttons still line up along the bottom. Here is the machinery:
- The outer
.deckdefines three named rows withgrid-template-rows: auto 1fr auto— one for titles, one for the (stretchy) text, one for buttons. - Each
.pcardusesgrid-row: span 3to stretch across all three of the deck’s rows. grid-template-rows: subgridis the key line: instead of the card inventing its own rows, it reuses the deck’s three rows. So every card’s title sits in row 1, text in row 2, button in row 3 — perfectly aligned with its neighbours.- Without subgrid, each card would size its rows alone and the buttons would land at different heights.
Note: Output: Three pricing cards in a row. Despite the middle card having far more description text, all three titles align, all three text areas align, and all three “Choose” buttons sit at exactly the same height along the bottom.
Tip: Subgrid is the missing piece for card decks, pricing tables and form rows where nested content must line up with the outer grid. It works the same way for columns with grid-template-columns: subgrid.
Q. What does grid-template-rows: subgrid do?
✍️ Practice
- Build a row of three cards with different text lengths and use subgrid so their buttons all align at the bottom.
- Use
grid-template-columns: subgridon a nested grid so its columns match the parent’s columns.
🏠 Homework
- Convert your pricing or feature section into a subgrid so every card’s rows line up no matter how long the text is.