Ronalds Vilciņš

Aligning Nested Layouts With CSS Subgrid

A nested CSS grid normally creates its own tracks. That is fine until its children need to line up with content in the parent grid. subgrid solves that specific problem by reusing the parent’s tracks.

Consider a parent with three columns:

HTML
<div class="grid-container">
  <div class="grid-item subgrid-container">
    <!-- Subgrid items here -->
  </div>
</div>
CSS
.grid-container {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
}

.subgrid-container {
  grid-column: 2 / 3;
  display: grid;
  grid-template-columns: subgrid;
}

The inner grid does not define a new set of column sizes. It uses the column tracks available where it sits in the parent grid.

Align card content using shared rows
View code
HTML
<label><input id="align" type="checkbox"> Use subgrid rows</label>
<div class="cards">
<article><h2>A short heading</h2><p>A short description.</p><a href="#" class="action">Read first note</a></article>
<article><h2>A much longer heading that wraps onto several lines</h2><p>This description is longer too, so the independent rows do not naturally line up.</p><a href="#" class="action">Read second note</a></article>
</div><p class="note">Toggle the checkbox and compare the starts of the descriptions and links.</p>
CSS
button, select { padding: .35rem .6rem; border: 1px solid var(--clg); background: var(--cw); color: var(--cb); }
input[type="range"] { width: min(100%, 18rem); vertical-align: middle; }
h2, h3 { font-size: 1rem; }
.note { color: var(--clg); }

.cards { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .75rem; margin-top: 1rem; }
article { display: grid; grid-template-rows: auto auto auto; gap: .75rem; border: 1px solid var(--clg); padding: .75rem; align-content: start; }
.cards.aligned article { grid-row: span 3; grid-template-rows: subgrid; }
h2, p { margin: 0; }
.note { margin-top: 1rem; }
JavaScript
document.querySelector('#align').addEventListener('change', event => {
  document.querySelector('.cards').classList.toggle('aligned', event.target.checked);
});
// These links demonstrate alignment, not navigation.
document.querySelectorAll('.action').forEach(link => link.addEventListener('click', event => event.preventDefault()));

Where subgrid is genuinely useful

Cards are a good example. Each card can be a grid item and also a grid container, while its title, description, and footer align with the same rows as the neighbouring cards. Without subgrid, those internal rows are independent, so content of different lengths pushes everything out of alignment.

You can inherit rows, columns, or both:

CSS
.card {
  display: grid;
  grid-row: span 3;
  grid-template-rows: subgrid;
}

The parent must already define the relevant tracks, and the subgrid must span them. That second detail is easy to miss when the result does not look like a grid at all.

Subgrid can also use the parent’s gaps, though you can override the gap on the subgrid when needed. I usually keep them consistent unless the design gives me a reason not to.

For a nested layout that does not need to align with anything outside itself, a normal grid is simpler. subgrid is not a replacement for Grid; it is the part you reach for when independent nested tracks are precisely the problem.

Filed under on

Last updated on

← Back to all articles