CSS Subgrid Tutorial: Achieving Perfect Card Layout Alignment

Use CSS Subgrid to perfectly align card content across rows without JavaScript or fixed heights.
This tutorial explains how CSS Subgrid solves the classic card layout alignment problem where titles, descriptions, and buttons become misaligned due to varying content lengths. Through a three-step approach—setting up a parent grid, spanning cards across rows, and enabling subgrid—you achieve automatic cross-card content alignment with just a few lines of CSS, eliminating the need for fixed heights or JavaScript workarounds.
In front-end development, card layouts are everywhere—product listings, blog posts, team pages all use them. But a long-standing problem has plagued developers: When card content varies in length, how do you keep all titles, body text, and footers perfectly aligned across cards?
In the past, we had to rely on fixed heights, JavaScript calculations, or various hacks. Now, a seriously underestimated CSS feature—Subgrid—can solve this problem elegantly.
The Classic Alignment Pain Point in Card Layouts
Imagine a typical scenario: you have a row of product cards, each containing an image, title, description, and footer (like a price or button). Since each product has different title lengths and description word counts, the heights of these content areas become uneven.
The result: the first card's title is one line, the second is two lines, causing all descriptions and buttons below to become misaligned. It looks visually messy and destroys the clean feel of the entire page.
Traditional solutions often require forcing fixed heights on each area, but this is inflexible and easily breaks with different content. Another common approach uses Flexbox with flex-grow to auto-expand a section, but this only pushes the footer to the bottom—it can't achieve cross-card row alignment. Subgrid was created precisely to let child elements "sense" and align to the parent grid's tracks.
How CSS Subgrid Works at Its Core
The entire approach can be divided into two layers: the parent grid and the card's own subgrid.
Before Subgrid, nested Grid containers created completely independent grid contexts—child element tracks had no relationship to the parent grid. Subgrid's core breakthrough lets nested grids "give up" their right to define their own tracks and instead directly use the parent grid's track lines. This means multiple sibling subgrid containers (like multiple cards in the same row) share the same row track definitions, achieving cross-container content alignment. This mechanism is declarative—the browser automatically calculates the maximum height needed for the same row track across all cards, then applies it uniformly.
Step 1: Set Up the Parent Grid Container
First, the container uses CSS Grid layout with auto-fit to automatically adapt the number of columns. This way, cards arrange intelligently based on available space, naturally providing responsive behavior.
.container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1rem;
}
Here, auto-fit is a keyword in CSS Grid's repeat() function that automatically calculates how many columns can fit based on the container's available width. Unlike auto-fill, auto-fit distributes excess space to existing columns when there aren't enough columns to fill the container, stretching them to fill. When used with minmax(200px, 1fr), each column is minimum 200px and can expand to fill remaining space, achieving a pure CSS responsive layout without media queries.

Step 2: Make Cards Span Multiple Rows
The key step is on the cards themselves. Each card has four content blocks (image, title, description, footer), so we make the card span four rows in the parent grid:
.product {
display: grid;
grid-row: span 4;
}
Interestingly, simply adding grid-row: span 4 produces no visual change. This step only "declares" that the card occupies four rows of space, preparing for the alignment in the next step.
The principle behind this involves CSS Grid's implicit track mechanism: when a child element uses grid-row: span N, if the parent hasn't explicitly defined enough rows (via grid-template-rows), Grid automatically creates "implicit tracks" to accommodate these elements. Implicit track default height is controlled by grid-auto-rows (default is auto, meaning sized by content). This is why adding span 4 alone produces no visual change—row heights are still determined by content automatically, but logically it prepares for subgrid inheritance.

Step 3: Enable Subgrid for Automatic Alignment
Finally, set the card's grid-template-rows to subgrid:
.product {
display: grid;
grid-row: span 4;
grid-template-rows: subgrid;
}
At this moment, all corresponding blocks across cards automatically align. All titles sit on the same horizontal line, all description areas have consistent heights, and all footers are neatly arranged. This is because subgrid lets child elements directly inherit and align to the parent grid's row tracks instead of acting independently. The browser traverses all cards in the same row, takes the maximum content height of each corresponding block as the unified height for that row track, achieving pixel-perfect cross-card alignment.
Handling Inconsistent Card Image Sizes
If card images vary too much in size, they can also affect the overall layout. There are two approaches:
The first is to go back to the parent grid and explicitly define row sizes, but this approach is somewhat inflexible because you need to worry about child element details at the parent level.

The second and more recommended approach is to control the size directly on the image element, such as setting a fixed height with object-fit:
.product img {
height: 100px;
object-fit: cover;
}
object-fit is a CSS property that controls how replaced elements (like <img>, <video>) fit within their container box. The cover value maintains the image's aspect ratio while scaling it to completely cover the container area, with excess parts being cropped. Other common values include contain (display completely but may leave whitespace), fill (stretch to fill, may distort), and none (maintain original size). When used with fixed width and height, object-fit: cover is the best practice for achieving uniform image display sizes, avoiding aspect ratio distortion issues.
This locks images at a uniform size while all other content blocks remain perfectly aligned through subgrid, producing a clean and orderly grid effect.

Why CSS Subgrid Is Worth Using Right Now
Subgrid is called an "underestimated feature" partly because its browser support lagged—only in recent years have mainstream browsers (Chrome, Firefox, Safari) fully supported it. Many developers' knowledge bases are still stuck on the impression that "subgrid can't be used."
Specifically, CSS Subgrid standardization went through a lengthy cycle. Firefox was first to implement support in 2019 (v71), but Chrome and Safari didn't follow until 2023 (Chrome 117, Safari 16.0). As of late 2024, global browser support exceeds 92%. For projects requiring legacy browser compatibility, you can use @supports (grid-template-rows: subgrid) for feature detection, providing a fallback layout (such as traditional Grid with fixed row heights). This progressive enhancement strategy lets modern browser users enjoy the best experience without completely breaking on older browsers.
On the other hand, many people mistakenly believe that achieving neat card alignment requires complex flexbox nesting or JavaScript. In reality, subgrid solves this classic front-end problem that has persisted for years with just a few lines of CSS, while fully preserving Grid's responsive capabilities (when used with auto-fit).
Summary of Subgrid Use Cases
Subgrid is particularly suited for:
- Aligning internal elements across multiple grid items (like card title rows, button rows)
- Dynamically varying content lengths where heights can't be predetermined
- Keeping code clean by avoiding JavaScript calculations or fixed-height hacks
- Form layouts where multiple form groups need aligned label and input columns
- Complex dashboards or data display pages where multiple panels need to share a unified grid rhythm
It's worth noting that Subgrid supports not only the row direction (grid-template-rows: subgrid) but also the column direction (grid-template-columns: subgrid), and can even use subgrid in both directions simultaneously for complete two-dimensional alignment inheritance.
For any front-end developer working with card layouts, subgrid deserves a place in your toolbox. It's not a flashy experimental feature—it's a mature solution that genuinely improves development efficiency and layout quality. Next time you encounter a "cards won't align" problem, consider reaching for it first.
Key Takeaways
Related articles

PPT Master: AI One-Click Generation of Native Editable PowerPoint Presentations
PPT Master is an open-source project with over 45K GitHub Stars that generates native editable .pptx files via AI, featuring data charts, animations, voice narration, and custom templates.

Delphi 13 Community Edition Free Download: The Classic RAD Tool for Cross-Platform Native Development Returns
Delphi 13 Community Edition is now available for free download. Explore its cross-platform native compilation, features, licensing, and Object Pascal's unique value in modern development.

GPT-5.6 Free Unlimited Conversations, Kimi K3 Officially Joins GitHub Copilot
OpenAI announces GPT-5.6 Luna unlimited free conversations, Kimi K3 becomes the first Chinese model in GitHub Copilot. Google releases WeatherNext, NVIDIA advances Physical AI infrastructure.