Home / Articles / Layout /

layoutgridsubgrid

Subgrid fundamentals: inheriting parent tracks

Subgrid solves a problem that has plagued CSS layouts since Grid launched: aligning content inside nested elements to the outer grid's tracks.

The problem subgrid solves

Without subgrid, each grid container defines its own independent set of tracks. Children of a grid item cannot see or align to the outer grid's columns or rows. This creates misalignment when you have cards with headers, bodies, and footers that need to line up across a row.

/* Without subgrid — each card has its own grid */
.card-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1.5rem;
}

.card {
  display: grid;
  grid-template-rows: auto 1fr auto;
  /* These rows are independent per card.
     If one card has a taller header, its body and footer
     shift down — other cards don't follow. */
}

The result: card headers, content areas, and footers at different vertical positions across the row. Subgrid fixes this by letting card children inherit row tracks from the parent grid.

Basic subgrid syntax

To use subgrid, a grid item must itself be a grid container. Then set grid-template-columns: subgrid or grid-template-rows: subgrid (or both) to inherit the parent's tracks for that axis.

.card-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: auto 1fr auto;  /* shared row tracks */
  gap: 1.5rem;
}

.card {
  display: grid;
  grid-row: span 3;              /* span all 3 row tracks */
  grid-template-rows: subgrid;   /* inherit parent's rows */
  /* Now .card's children align to the parent's row tracks.
     All card headers share the same row height. */
}

.card__header  { /* auto-placed in row 1 */ }
.card__body    { /* auto-placed in row 2 */ }
.card__footer  { /* auto-placed in row 3 */ }
The grid item must span the correct number of parent tracks. If the parent has 3 row tracks, the subgrid child needs grid-row: span 3 to access all of them.

Subgrid on one axis only

You can use subgrid on one axis and define independent tracks on the other. This is the most common pattern — inherit row alignment while keeping columns independent (or vice versa).

/* Inherit rows from parent, define own columns */
.card {
  display: grid;
  grid-row: span 3;
  grid-template-rows: subgrid;       /* inherits parent rows */
  grid-template-columns: 4rem 1fr;   /* own column definition */
  gap: 0.75rem;
}

/* Inherit columns from parent, define own rows */
.table-row {
  display: grid;
  grid-column: 1 / -1;               /* span all parent columns */
  grid-template-columns: subgrid;    /* inherits parent columns */
  grid-template-rows: auto;          /* own row definition */
}

Gap behaviour in subgrid

By default, a subgrid inherits the parent grid's gap values. You can override the gap on the subgrid container to use different spacing for the child items — but the track lines themselves remain aligned with the parent.

.parent {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 2rem;
}

.child {
  display: grid;
  grid-column: span 4;
  grid-template-columns: subgrid;
  gap: 0.5rem;  /* overrides parent's 2rem gap */
  /* Track lines still align with parent,
     but spacing between this element's children is 0.5rem */
}

Real-world example: aligned card grid

This is the canonical subgrid use case. A row of cards where every header, body, and footer lines up perfectly, regardless of content length.

.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  grid-auto-rows: auto 1fr auto;  /* repeating 3-row pattern */
  gap: 1.5rem;
}

.card {
  display: grid;
  grid-row: span 3;
  grid-template-rows: subgrid;
  border-radius: 0.5rem;
  background: oklch(0.19 0.02 260);
  overflow: hidden;
}

.card__image {
  /* Row 1 — all images share the same row height */
  aspect-ratio: 16 / 9;
  object-fit: cover;
  width: 100%;
}

.card__body {
  /* Row 2 — grows to fill, pushing footer down */
  padding: 1rem;
}

.card__footer {
  /* Row 3 — all footers align at the bottom */
  padding: 0.75rem 1rem;
  border-top: 1px solid oklch(0.3 0.02 260);
}

Nested subgrid (grandchild alignment)

Subgrid can chain through multiple levels. A grandchild can align to the outermost grid by having both the child and grandchild use subgrid. This enables deeply nested content to participate in a single top-level grid.

.outer {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 1rem;
}

.middle {
  display: grid;
  grid-column: span 6;
  grid-template-columns: subgrid;  /* inherits outer's 6 cols */
}

.inner {
  display: grid;
  grid-column: 2 / 5;              /* span 3 of the 6 cols */
  grid-template-columns: subgrid;  /* inherits those 3 tracks */
}

/* .inner's children now align to columns 2–4 of .outer */
Subgrid is supported in all major browsers since December 2023 (Chrome 117, Firefox 71, Safari 16). Check caniuse.com/css-subgrid for the latest data.