Brand New Layouts with CSS Subgrid
Brand New Layouts with CSS Subgrid

### Unlocking New Layouts: A Deep Dive into CSS Subgrid
For years, CSS Grid has been the undisputed champion of two-dimensional web layouts. It gave us unprecedented power to arrange elements into columns and rows, finally freeing us from the hack-filled era of floats and table layouts. But even with all its power, Grid had one frustrating limitation: a grid item creates a new, independent formatting context. The parent grid’s tracks stopped at the item’s boundary, and any grid inside that item was a completely separate universe.
This meant aligning items *within* different grid children was a nightmare. We resorted to fixed heights, JavaScript, or the occasionally problematic `display: contents`. But now, the wait is over. Enter CSS Subgrid.
#### The Problem Subgrid Solves
Imagine a common UI pattern: a row of cards. Each card has a title, some body text, and a “Read More” button at the bottom. The design calls for all the card titles to be aligned, the body sections to start at the same height, and all the buttons to be perfectly lined up at the bottom, regardless of the amount of content in each card.
With a standard CSS Grid, this is deceptively difficult.
“`html
A Much Longer and More Descriptive Title
This card has significantly more content in its body. It will stretch the height and throw off the alignment of the elements in the other cards.
“`
If you make `.card-container` a grid, you can align the cards themselves. But the `h3`, `p`, and `a` tags inside each `.card` have no knowledge of their counterparts in the sibling cards. The result is a messy, unaligned layout.
This is precisely the problem Subgrid was designed to fix.
#### How Subgrid Works: Inheriting the Grid
Subgrid is not a new display type. It’s a new value for `grid-template-columns` and `grid-template-rows`.
When you set `grid-template-rows: subgrid;` on a grid item, you’re telling that element: “Don’t create your own row tracks. Instead, borrow the row tracks from your parent grid that you are currently occupying.” The same logic applies to `grid-template-columns: subgrid;`.
A subgridded item doesn’t get the *entire* parent grid, just the portion it spans. If a parent has 12 columns and an item spans columns 4 through 8, its subgrid will consist of those specific five columns.
#### Let’s Fix Our Cards
To solve our card alignment problem, we need to make the parent container define the “master” grid for the card’s internal structure.
First, we set up the parent container. We’ll define columns for our cards, but crucially, we’ll also define three rows: one for the title (sized by its content), one for the body (which will take up the remaining space), and one for the button (sized by its content).
“`css
.card-container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
grid-template-rows: auto 1fr auto; /* Title, Body, Button */
gap: 20px;
}
“`
Now, the magic. We tell each card to become a grid container itself, but to *subgrid* its rows. We also need to ensure each card spans all three of the parent’s row tracks.
“`css
.card {
display: grid;
grid-row: span 3; /* Make the card occupy all 3 parent rows */
grid-template-rows: subgrid; /* This is the key! */
/* Optional: Add some styling */
border: 1px solid #ccc;
border-radius: 8px;
padding: 1rem;
}
“`
With this in place, the `h3`, `p`, and `a` elements inside *every* card are now participating in the *same* three-row grid defined on `.card-container`. The first row track across the entire layout is defined by the tallest title, the third row track is defined by the tallest button, and the middle row track flexes to fill the space.
All that’s left is to place the items onto this new, shared grid.
“`css
.card h3 {
grid-row: 1; /* Place in the first (title) subgrid row */
}
.card p {
grid-row: 2; /* Place in the second (body) subgrid row */
}
.card .button {
grid-row: 3; /* Place in the third (button) subgrid row */
align-self: end; /* Nice for vertical alignment */
}
“`
The result? Perfect alignment across all cards, no matter the content.
#### Subgridding Both Axes
You aren’t limited to just rows or columns. You can use subgrid on both axes simultaneously. This is incredibly powerful for modular components that need to align with a larger, page-level “master” grid.
Consider a page with a main 12-column layout. You have a featured article component that spans 8 of those columns. Inside that component, you have an image and a text block that you want to align with the underlying 12-column structure.
“`css
.page-wrapper {
display: grid;
grid-template-columns: repeat(12, 1fr);
gap: 20px;
}
.featured-article {
grid-column: 2 / 10; /* Span from column line 2 to 10 */
/* Set up the subgrid */
display: grid;
grid-template-columns: subgrid;
}
.featured-article .image {
/* This now refers to the parent’s columns */
grid-column: 1 / 5; /* Occupy the first 4 columns of the subgrid */
}
.featured-article .text {
/* Occupy the last 4 columns of the subgrid */
grid-column: 5 / 9;
}
“`
The `.image` and `.text` elements are now perfectly aligned to the main page grid, even though they are nested inside another element. This creates a harmonious, visually consistent layout that is both robust and easy to maintain.
Subgrid is a subtle but revolutionary addition to CSS. It bridges the gap between parent and child grids, solving a class of problems that once required complex workarounds. It encourages more semantic HTML and cleaner CSS, leading to layouts that are more resilient and easier to reason about. It’s well-supported in all modern browsers, so there’s no reason not to start experimenting with it today.
