CSS Subgrid Rows: Aligning Cards in Dynamic Lists
This article explores how the CSS subgrid value for
grid-template-rows solves the common problem of misaligned
content within dynamic card layouts. You will learn the mechanics of
grid-template-rows: subgrid, the limitations of traditional
layout methods, and a practical implementation to align card headers,
bodies, and footers consistently across adjacent grid columns regardless
of dynamic content size.
The Problem with Dynamic Card Layouts
In modern web design, dynamic card lists frequently contain varying amounts of content. One card may have a single-line title and short description, while an adjacent card contains a three-line title and lengthy text.
Using traditional CSS Grid or Flexbox, the outer card boundaries can easily stretch to match the height of the tallest card in a row. However, the internal sections of those cards—such as headers, body content, and call-to-action buttons—remain isolated within each card's local layout context. This causes buttons and text sections to sit at mismatched vertical positions across the row, creating an uneven visual rhythm.
What is
grid-template-rows: subgrid?
Normally, setting display: grid on a child element
creates a completely independent grid context disconnected from the
parent grid's tracks.
The subgrid value changes this behavior. When applied to
a nested grid container via grid-template-rows: subgrid,
the child element adopts the row tracks defined by its parent grid
instead of generating its own independent row tracks. This allows direct
descendants of the nested container to place themselves along the parent
grid's tracks, sharing sizing calculations directly with neighboring
cards.
How Subgrid Aligns Cards in Dynamic Lists
To align internal card components across dynamic columns, the layout relies on two structural requirements:
- The parent grid spans multiple rows per card: Instead of each card occupying a single grid row, the parent grid allocates multiple rows (such as one for the header, one for the body, and one for the footer).
- The card uses subgrid for its rows: The card
container spans these rows (for example,
grid-row: span 3) and declaresgrid-template-rows: subgrid.
Because the cards share the exact same row tracks, an expanding element in one card expands that row for every other card in the same horizontal track. If one card has a three-line title, the shared header row grows, neatly pushing the body and footer down uniformly across all cards in that row.
Practical Implementation
HTML Structure
<div class="card-grid">
<article class="card">
<h3>Short Title</h3>
<p>Brief text description.</p>
<button>Read More</button>
</article>
<article class="card">
<h3>A Much Longer Title That Wraps Across Multiple Lines</h3>
<p>Detailed text description that takes up more vertical space.</p>
<button>Read More</button>
</article>
</div>CSS Implementation
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
/* Automatically create rows sized by content */
grid-auto-rows: auto auto auto;
gap: 1.5rem;
}
.card {
display: grid;
/* Span across the 3 parent rows: header, body, footer */
grid-row: span 3;
/* Inherit the row track sizing from .card-grid */
grid-template-rows: subgrid;
border: 1px solid #ccc;
padding: 1rem;
}Summary of Benefits
Using grid-template-rows: subgrid for card lists
provides several distinct advantages:
- Pixel-perfect alignment: Headers, paragraphs, and action buttons align horizontally across dynamic sibling elements without fixed heights.
- No JavaScript needed: Layout calculations are handled entirely in the browser's native rendering engine, eliminating the need for resize listeners or script-based height equalization.
- Responsive and dynamic: The layout automatically adjusts when screen sizes change or when new content loads dynamically via APIs.