Skip to content

CSS Subgrid: Aligning Nested Grids to Parent Tracks

CSS subgrid lets nested grids inherit the parent's tracks, so card titles, bodies, and footers line up across a whole grid. Support is about 97% in 2026.

· · 13 min read

Updated: October 16, 2026

Assorted colour layout sketches on paper

Quick Take

CSS subgrid lets a nested grid borrow its parent's row or column tracks instead of creating its own, so elements inside separate children line up on the same lines. It's Baseline widely available as of March 2026 and sits near 97% global support.

Run this yourself. The measurement behind the alignment table: css-subgrid-row-alignment/ in the Coding Dunia code-examples repo. It lays out the same twelve cards four ways and prints where every title, body and footer landed.

This guide gets CSS subgrid explained with the exact problem it fixes, working code, and the browser support numbers you need before shipping it. CSS subgrid solves one specific, annoying problem: nested grids don't share track lines with their parent, so content inside separate children drifts out of alignment. You set grid-template-rows: subgrid (or columns) on a grid item that is itself a grid, and its children start measuring against the parent's tracks. Subgrid reached Baseline widely available in March 2026 and sits near 97% global support. I reach for it any time a card layout needs pixel-perfect rows without me hard-coding heights.

What problem does CSS subgrid solve?

Picture a product grid. Each card holds a title, a description, and a price footer. The titles are different lengths - some wrap to two lines, some stay on one. The descriptions vary too. Without subgrid, each card is its own little grid, and each card sizes its rows from its own content. The result? Prices float at different heights. Titles push the body down by different amounts. The whole row looks crooked.

Here's the thing. The parent grid does know where the columns are, so the cards themselves line up left to right. But the parent has no idea what's happening inside each card. A child grid's rows are private. That internal misalignment is exactly what subgrid fixes.

/* The outer grid: three columns of cards */
.product-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1.5rem;
}

/* Each card is a normal grid here - and its rows DON'T match its neighbours */
.card {
  display: grid;
  grid-template-rows: auto 1fr auto;
}

That grid-template-rows: auto 1fr auto looks reasonable. But auto means "as tall as this card's title," which differs card to card. So the middle rows never agree.

How does the subgrid keyword work?

The fix is to give the outer grid explicit row tracks, then tell each card to inherit them. You do that with the subgrid keyword. When a grid item spans some of the parent's tracks and sets grid-template-rows: subgrid, it stops inventing its own rows. It adopts the parent's.

.product-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  /* Define the shared rows ON THE PARENT */
  grid-template-rows: auto 1fr auto;
  gap: 1.5rem;
}

.card {
  display: grid;
  /* Span all three parent rows, then borrow them */
  grid-row: span 3;
  grid-template-rows: subgrid;
}

Now every card measures its title, body, and footer against the same three lines. The tallest title in the whole grid sets the height of the first row, and every other card respects it. Same for the body and footer. Notice the parent defines the tracks once, and the children just point at them with a single keyword. Isn't that cleaner than the alternative?

The parent defines the tracks once, and the children just point at them with a single keyword - isn't that cleaner than the alternative?

Share this Post on X Bluesky

You can do the same on the column axis with grid-template-columns: subgrid, and you can use both at once. Each axis is independent.

A concrete building facade built from a repeating grid of panels next to a spiral staircase
Photo by Declan Sun on Unsplash

What Does a Card Grid with Aligned Rows Look Like?

Let me show the full thing - markup plus CSS - so the alignment is concrete. Three stacked rows (title, body, footer) that agree across all cards.

<div class="product-grid">
  <article class="card">
    <h3 class="card__title">Compact wide-angle lens for mirrorless bodies</h3>
    <p class="card__body">A short description that runs a couple of lines.</p>
    <div class="card__footer"><span>$249</span><button>Add</button></div>
  </article>

  <article class="card">
    <h3 class="card__title">Tripod</h3>
    <p class="card__body">A much longer description that keeps going and wraps onto three or even four lines depending on the width.</p>
    <div class="card__footer"><span>$79</span><button>Add</button></div>
  </article>
</div>
.product-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  grid-template-rows: auto 1fr auto;
  gap: 1.5rem;
}

.card {
  display: grid;
  grid-row: span 3;
  grid-template-rows: subgrid;
  border: 1px solid #2a2a2a;
  border-radius: 8px;
  padding: 1rem;
}

.card__footer {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

The first card has a long two-line title and a short body. The second has a one-word title and a four-line body. Without subgrid, their footers would sit at wildly different heights. With it, the footers line up on the same baseline, and so do the titles. The gap between rows even inherits from the parent's gap, which a plain nested grid can't do, and which can also surprise you, as the measurements below show.

Subgrid vs a Normal Nested Grid: Which Should You Use?

So when do you use which? A plain nested grid is the right call when a component's internal layout is nobody else's business - a settings panel, a form section, a self-contained widget. Its rows and columns should size from its own content, full stop.

Subgrid is the right call the moment children of different parents need to agree with each other. Card grids, comparison tables built from divs, timeline entries, any repeating unit where a shared baseline matters. The rule I use: if misalignment between siblings would look like a bug, reach for subgrid.

Before subgrid landed, I faked this with fixed heights. I'd set min-height: 3.2rem on every title so two-line and one-line titles occupied the same space, then pray nobody wrote a three-line title. It broke constantly. New copy came in, a title wrapped further than I'd budgeted, and the footers drifted again. Subgrid deletes that whole category of hack. My honest opinion? For any card grid with variable-length content, subgrid is worth it even at a small support cost - the fixed-height workaround is more fragile and needs babysitting every time the copy changes. For a one-off layout where nothing repeats, don't bother; a normal grid is simpler.

If you're still deciding between the two-dimensional power of Grid and the one-dimensional simplicity of Flexbox for the outer container itself, the CSS Grid vs Flexbox comparison walks through that decision with concrete examples.

How Much Better Is Subgrid Than the Usual Workarounds, Measured?

"Subgrid aligns the rows" is true and nobody disputes it. What I couldn't find in any guide was the other half: what the alternatives actually do across a range of widths, and what alignment costs. So I built the same twelve cards four ways and asked headless Chromium where everything landed, using getBoundingClientRect() rather than my eyes. Chromium 151.0.7922.34 (Playwright 1.62.1, Node 22.23.3), Apple M1, 2026-10-16. Nothing in this test is timed, so the machine being busy with other jobs doesn't matter, and two runs produced byte-identical output.

The cards have titles from one word to a 15-word sentence, bodies from one to four sentences, and a one-line footer. The grid is repeat(auto-fit, minmax(260px, 1fr)) with a 24px gap, and the four builds are:

  • subgrid: the card spans three parent rows with grid-template-rows: subgrid
  • nested: the card is its own grid, grid-template-rows: auto 1fr auto
  • flex: the card is a flex column with margin-top: auto on the footer, the other common trick
  • fixed: the flex column plus min-height on the title (three lines) and body (four lines), calibrated at one width

For each visual row of cards I measured how far apart the body tops and the footer tops were, in pixels, and kept the worst row. Then I swept the container from 300px to 1300px in 5px steps, 201 widths, 152 of which are wide enough for two or more columns. At 1240px, 940px and 620px:

ContainerBuildWorst body-top spreadWorst footer-top spreadGrid height
1240px, 4 columnssubgrid0px0px1008.6px
nested78px0px982.6px
flex78px0px982.6px
fixed26px0px1086.6px
940px, 3 columnssubgrid0px0px1273.3px
nested52px0px1221.3px
flex52px0px1221.3px
fixed0px0px1377.3px
620px, 2 columnssubgrid0px0px1668.4px
nested52px0px1642.4px
flex52px0px1642.4px
fixed0px0px1876.5px

Three things in that table I hadn't expected.

First, margin-top: auto pins the footers perfectly and does nothing for the bodies. That's the trick most tutorials teach as the card-alignment fix. The footer spread is 0px in every row, so it looks solved in a screenshot of the bottom edge, while the body text starts up to 78px apart, which is three title lines at 26px each. Nested grid and flex gave identical numbers at every width, and across the sweep neither had a single multi-column width where body tops lined up: 0 of 152.

Second, the fixed-height guess. I calibrated it at 940px, and it's perfect there, and at 620px. Over the whole sweep it kept body tops aligned at only 86 of the 152 multi-column widths, 57%. It failed at the other 66, and at 1240px the tops were 26px apart, which is one line of title running past its allowance. It also wastes room: in the table it makes the grid 104px taller than subgrid at 940px, 208px taller at 620px, and at 300px, where nothing needs aligning because the cards stack in one column, it reserves 654px of padding for nothing (3,642.7px against 2,988.1px).

Third, subgrid is not free. Look at the height column. Subgrid made the grid taller than the nested version at all 152 multi-column widths: 26px at 1240px, 52px at 940px, 26px at 620px, and 38px on average across the sweep, from 22px at the least to 78px at the most. The reason is arithmetic. A nested card only has to be as tall as its own title plus its own body. A subgrid row has to be as tall as the tallest title in the row plus the tallest body in the row, so the short card pays for its neighbours' longest parts. That's the price of aligned lines, and it's small, but it's real and nobody mentions it.

Across 152 container widths, subgrid kept card rows aligned at every one, nested grid and a flex column with margin-top auto at none, and a calibrated min-height guess at 57 percent, at a cost of 38px of extra grid height on average.

Share this Post on X Bluesky

One more number, from the gap I called "a nice touch" earlier. When the card doesn't set its own row-gap, a subgrid inherits the parent's. My parent gap was 24px, and without an override the distance from title to body measured 24px. Setting row-gap: 12px on the card gave 12px. If your cards look airier after you switch to subgrid, that's why.

Limits, plainly. One engine, so Firefox and Safari may place sub-pixel boundaries differently even though the alignment logic is the same. One content set: my titles and bodies were chosen to disagree, and a grid whose cards all have equally long text would show no difference between any of these builds. And "aligned" here means the tops of the body and footer, not the baselines of the text inside them.

A woven metallic building facade with a regular grid pattern against a clear blue sky
Photo by Maarten Deckers on Unsplash

What Is the Browser Support and How Do You Add a Fallback?

Subgrid has a longer history than people assume. Firefox shipped it back in version 71 in late 2019, and it sat there alone for nearly three years.

BrowserFirst version with subgridShipped
Firefox71December 2019
Safari16.0September 2022
Chrome117September 2023
Edge117September 2023
Opera103September 2023
Samsung Internet24Late 2023

Chrome 117 completed the set in September 2023, which made subgrid Baseline newly available. The widely available badge came later, on 15 March 2026, since that status waits 30 months after the last major engine ships. Worth keeping the two apart: plenty of posts collapse them and make the feature sound older or newer than it is. Global support now sits around 97% according to caniuse.

Still, 97% isn't 100. Guard it with @supports so older browsers get a sane layout instead of a broken one.

.card {
  display: grid;
  grid-template-rows: auto 1fr auto; /* fallback: each card sizes itself */
}

@supports (grid-template-rows: subgrid) {
  .product-grid {
    grid-template-rows: auto 1fr auto;
  }
  .card {
    grid-row: span 3;
    grid-template-rows: subgrid; /* the shared-track upgrade */
  }
}

Browsers without subgrid keep the plain nested grid. The footers won't be perfectly aligned there, but the cards still stack cleanly and read fine. No JavaScript, no polyfill, no layout explosion. That's a graceful degrade, and for a purely cosmetic alignment feature it's exactly the right trade.

One last practical note. Track spanning is the requirement that a subgrid item must claim, via grid-row: span N or grid-column: span N, exactly the number of parent tracks it wants to inherit before the subgrid keyword has anything to borrow. Subgrid only inherits tracks it actually spans, so the child has to grid-row: span N (or grid-column: span N) across the parent lines you want to borrow. Forget the span and the keyword quietly does nothing. Check the MDN subgrid reference if the alignment isn't taking - it's almost always a missing span.

If a card's rows still refuse to line up after adding subgrid, work through this order before filing it as a browser bug.

  1. Confirm the parent actually defines named or explicit tracks, grid-template-rows: auto 1fr auto, not grid-auto-rows, since subgrid inherits explicit tracks only.
  2. Confirm the child has a matching grid-row: span N (or grid-column: span N) that covers exactly the tracks you expect it to borrow.
  3. Open DevTools' grid inspector and toggle the subgrid overlay, most browsers now draw the inherited lines directly so you can see which tracks actually got adopted.
  4. If the layout is still off, check for an intermediate wrapper element between parent and child, subgrid does not skip a level automatically.
  • CSS nesting vs Sass - where native nesting still falls short of Sass, and what that costs a subgrid layout's stylesheet
  • CSS Container Queries - make each subgrid-aligned card adapt to its own width, not just the viewport

Frequently Asked Questions

What does CSS subgrid actually do?
Subgrid lets a nested grid adopt the track sizes of its parent grid instead of defining its own. You set grid-template-columns or grid-template-rows to the keyword subgrid on a grid item that is itself a grid. Its children then align to the parent's lines, not to lines the child invented.
What is the difference between subgrid and a normal nested grid?
A normal nested grid sizes its tracks from its own content, so two sibling cards can end up with mismatched rows. Subgrid pulls the track definitions down from the parent, so every child shares the same lines. Use a nested grid when a component's internal layout is private, and subgrid when children must align with each other.
What is the browser support for CSS subgrid?
Subgrid shipped in Firefox 71 in 2019, then Safari 16 in 2022 and Chrome 117 in September 2023, which made it Baseline newly available. It reached Baseline widely available on 15 March 2026, since that badge waits 30 months after the last major engine ships. Global support sits around 97% as of 2026 according to caniuse.
Can you use subgrid for both rows and columns?
Yes. You can set grid-template-columns: subgrid, grid-template-rows: subgrid, or both on the same element. Each axis is independent, so a card can inherit the parent's three row tracks while still defining its own columns.
How do I provide a fallback for browsers without subgrid?
Wrap the subgrid rules in @supports (grid-template-columns: subgrid). Browsers that lack support keep the plain nested-grid layout, which stacks and reads fine even if the rows don't align perfectly. No polyfill is needed for a graceful degrade.