Subgrid & Masonry
When you need nested grids to line up, and the masonry future.
Once you can spin up a Grid in your sleep, you start running into problems that need the deeper toolkit: nested grids that need to align with their parent, Pinterest-style masonry, weirdly shaped overflow, and the never-ending question of "where did this extra row come from?" This lesson covers the advanced features that turn Grid from useful into magical.
Explicit vs implicit grid
Everything you write in grid-template-columns and grid-template-rows is the explicit grid. The moment you place an item beyond those tracks, the browser creates the implicit grid. Its tracks are sized by grid-auto-columns and grid-auto-rows, which default to auto(meaning "fit content").
.list {
display: grid;
grid-template-columns: 1fr 1fr; /* explicit: two columns */
grid-auto-rows: 100px; /* implicit rows are all 100px */
gap: 8px;
}Drop fifty children into that container and you get twenty-five rows, each 100px tall. You never declared the rows. Grid created them because items needed cells.
Dense packing fills the holes
Normally Grid places items in source order. If item three is too wide to fit in row one, Grid leaves a hole and puts it in row two. The dense keyword on grid-auto-flow changes that: Grid will go back and fill earlier holes with later items that fit.
.gallery {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-auto-flow: dense; /* fill any earlier holes */
gap: 12px;
}grid-auto-flow: densecan scramble the visual order relative to the DOM order. Screen readers still announce in DOM order, so don't use it for content that depends on sequence (like a numbered list or a step-by-step tutorial). Great for image galleries, dangerous for articles.Subgrid: nested alignment that actually aligns
Subgrid is one of the most-requested features in CSS history, and it finally landed in every evergreen browser by 2023. Without subgrid, a nested grid has its own track sizing that doesn't know about the parent. With subgrid, the child grid inheritsthe parent's tracks. Headers, body, and footers in a row of cards can line up perfectly even if each card has different content.
.cards {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: auto 1fr auto; /* header / body / footer */
gap: 16px;
}
.card {
display: grid;
grid-row: span 3; /* take all three rows */
grid-template-rows: subgrid; /* inherit parent's row sizing */
}Now every card's header sits on the parent's first row, body on the second, footer on the third. If one card has a long title, every card's header grows together. No JavaScript, no equal-height hacks.
Masonry: like Pinterest, in pure CSS
Masonry layout (uneven rows, vertically packed columns) used to require a JavaScript library. CSS masonry is now shipping in browsers as grid-template-rows: masonry (and behind a flag in some). The exact syntax is still being standardized. As of 2026 you can use it like this:
.pinboard {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
grid-template-rows: masonry; /* let Grid pack vertically */
gap: 12px;
}@supports (grid-template-rows: masonry) {
.pinboard { grid-template-rows: masonry; }
}Subgrid in action
Three cards, each with a title, body, and footer. Each card has different content length, but everything lines up because we use subgrid. Try removing the subgrid line and watch the alignment fall apart.
Naming areas with subgrid
Subgrid can inherit named lines from the parent. Combined with grid-template-areas, you get layouts where parents and children share a vocabulary, and you only define alignment in one place. This becomes essential in design systems where dozens of card variants all need to align identically.
Anti-pattern: 100% width children
New Grid users sometimes set width: 100% on grid children, which is redundant. Grid already gives the child the cell width. Adding width: 100% can cause overflow when the child has padding. Trust the cell.
Quiz
What does grid-auto-flow: dense do?
Recap
- Explicit grid: what you declare. Implicit grid: what Grid generates when items spill past your tracks.
grid-auto-flow: densebackfills holes. Great for galleries, bad for content order.- Subgrid inherits track sizing from the parent so nested layouts align perfectly.
- CSS masonry is shipping (with uneven support). Wrap it in
@supportsfor safety. - Don't set
width: 100%on grid children. The cell already does that.