CSS Subgrid: Nested Grid Alignment Made Easy
CSS Subgrid solves one of the most persistent challenges in web layout: aligning nested content with parent grid tracks. Before subgrid, nested grids were independent, making it nearly impossible to align items across different nesting levels without complex calculations or JavaScript.
The Problem Subgrid Solves
Consider a common scenario: a card grid where each card has a header, content, and footer. Without subgrid, each card's internal sections can't align with cards beside them.
/* Without subgrid - each card has independent row sizing */
.card-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
}
.card {
display: grid;
grid-template-rows: auto 1fr auto;
/* These rows are independent - can't align across cards */
}Introducing Subgrid
Subgrid allows a nested grid item to adopt the track sizing of its parent grid, creating perfect alignment across nesting levels.
.card-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: auto 1fr auto;
gap: 20px;
}
.card {
display: grid;
grid-row: span 3; /* Span all three parent rows */
grid-template-rows: subgrid; /* Adopt parent's row tracks */
}Now every card's header aligns perfectly with other headers, regardless of content length.
Subgrid Syntax
Subgrid can be applied to either grid-template-columns, grid-template-rows, or both.
.parent {
display: grid;
grid-template-columns: 200px 1fr 200px;
grid-template-rows: auto 1fr auto;
}
/* Subgrid on rows only */
.child-rows {
display: grid;
grid-row: 1 / -1;
grid-template-rows: subgrid;
grid-template-columns: 1fr 1fr; /* Own column definition */
}
/* Subgrid on columns only */
.child-cols {
display: grid;
grid-column: 1 / -1;
grid-template-columns: subgrid;
grid-template-rows: auto auto; /* Own row definition */
}
/* Subgrid on both axes */
.child-both {
display: grid;
grid-column: 1 / -1;
grid-row: 1 / -1;
grid-template-columns: subgrid;
grid-template-rows: subgrid;
}Practical Example: Card Grid
Here's a complete example of aligned cards using subgrid.
.card-container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
/* Define row structure that cards will adopt */
grid-template-rows: auto auto 1fr auto;
gap: 24px;
}
.card {
display: grid;
grid-row: span 4; /* Span all four rows */
grid-template-rows: subgrid;
gap: 0; /* Override parent gap if needed */
background: white;
border-radius: 12px;
overflow: hidden;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.card-image {
/* First row - auto height based on content */
aspect-ratio: 16/9;
object-fit: cover;
width: 100%;
}
.card-title {
/* Second row - auto height */
padding: 16px 16px 8px;
font-size: 1.25rem;
font-weight: 600;
}
.card-description {
/* Third row - flexible (1fr) */
padding: 0 16px;
color: #666;
}
.card-footer {
/* Fourth row - auto height */
padding: 16px;
border-top: 1px solid #eee;
}Subgrid with Named Lines
When a parent grid uses named lines, subgrid children can reference them.
.parent {
display: grid;
grid-template-columns:
[sidebar-start] 250px
[sidebar-end content-start] 1fr
[content-end];
grid-template-rows:
[header-start] auto
[header-end main-start] 1fr
[main-end footer-start] auto
[footer-end];
}
.full-width-child {
grid-column: 1 / -1;
grid-row: 1 / -1;
display: grid;
grid-template-columns: subgrid;
grid-template-rows: subgrid;
}
.full-width-child .header {
grid-column: sidebar-start / content-end;
grid-row: header-start / header-end;
}
.full-width-child .sidebar {
grid-column: sidebar-start / sidebar-end;
grid-row: main-start / main-end;
}Subgrid Gaps
By default, subgrid inherits the parent's gap. You can override this with the gap property on the subgrid container.
.parent {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 20px;
}
.child {
grid-column: span 4;
display: grid;
grid-template-columns: subgrid;
/* Override inherited gap */
gap: 10px;
/* Or different gaps for rows/columns */
row-gap: 5px;
column-gap: inherit; /* Keep parent's column gap */
}Form Layout with Subgrid
Subgrid excels at form layouts where labels and inputs need to align.
.form {
display: grid;
grid-template-columns: max-content 1fr;
gap: 16px 24px;
}
.form-group {
display: grid;
grid-column: span 2;
grid-template-columns: subgrid;
align-items: center;
}
.form-group label {
/* Aligns with all other labels */
text-align: right;
}
.form-group input {
/* All inputs start at same column */
padding: 8px 12px;
border: 1px solid #ddd;
border-radius: 4px;
}<form class="form">
<div class="form-group">
<label>Full Name</label>
<input type="text">
</div>
<div class="form-group">
<label>Email Address</label>
<input type="email">
</div>
<div class="form-group">
<label>Phone</label>
<input type="tel">
</div>
</form>Table-Like Layouts
Create semantic, accessible table-like layouts without actual tables.
.data-grid {
display: grid;
grid-template-columns: 1fr 2fr 1fr 1fr;
}
.data-row {
display: grid;
grid-column: 1 / -1;
grid-template-columns: subgrid;
padding: 12px 0;
border-bottom: 1px solid #eee;
}
.data-row:first-child {
font-weight: bold;
background: #f8f8f8;
}
.data-cell {
padding: 0 16px;
}Nested Subgrids
Subgrid can be nested multiple levels deep.
.grandparent {
display: grid;
grid-template-columns: repeat(6, 1fr);
gap: 20px;
}
.parent {
grid-column: span 6;
display: grid;
grid-template-columns: subgrid;
}
.child {
grid-column: span 3;
display: grid;
grid-template-columns: subgrid; /* Still references grandparent's tracks */
}Browser Support
Subgrid has good support in modern browsers (Chrome 117+, Firefox 71+, Safari 16+). For older browsers, provide fallbacks.
/* Fallback for browsers without subgrid */
.card {
display: grid;
grid-template-rows: auto 1fr auto;
}
/* Subgrid enhancement */
@supports (grid-template-rows: subgrid) {
.card-container {
grid-template-rows: auto auto 1fr auto;
}
.card {
grid-row: span 4;
grid-template-rows: subgrid;
}
}Summary
CSS Subgrid eliminates the alignment challenges of nested grids by allowing children to participate in their parent's track sizing. It's invaluable for card layouts, forms, data displays, and any situation where content at different nesting levels needs to align. Combined with named lines and gap inheritance, subgrid makes complex layouts achievable with clean, maintainable CSS.