CSS Subgrid

What You'll Learn

  • How subgrid allows nested grids to inherit their parent's grid tracks
  • Using grid-template-rows: subgrid and grid-template-columns: subgrid
  • Solving the alignment problem in card grids and form layouts
  • Understanding when to use subgrid vs nested grids
  • Creating perfectly aligned nested grid content without manual synchronization
  • Best practices for subgrid implementation

Introduction to Subgrid

Subgrid is a powerful CSS Grid feature that allows grid items to inherit the grid tracks (rows or columns) of their parent grid. This solves a longstanding problem: aligning nested grid content across siblings. Before subgrid, keeping elements like card footers or form labels aligned required complex workarounds or JavaScript.

With subgrid, a grid item can declare display: grid; grid-template-rows: subgrid; and its children will align to the parent's row tracks. This creates perfect alignment without manual coordination, making complex layouts like card grids and forms much simpler to implement.

The Problem: Without Subgrid

Consider a card grid where each card has a title, description, and button. Without subgrid, cards with different content lengths will have misaligned buttons—each card creates its own independent grid.

Example Without Subgrid

.grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; } .card { display: grid; grid-template-rows: auto 1fr auto; /* Each card has its own grid - buttons won't align! */ }

Result: Misaligned Elements

Notice how the buttons appear at different heights because each card's grid is independent.

The Solution: With Subgrid

By using subgrid, the cards inherit the parent's grid rows, ensuring perfect alignment of titles, content, and buttons across all cards regardless of content length.

Syntax

.grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; } .card { display: grid; grid-template-rows: subgrid; /* Inherit parent's rows! */ grid-row: span 3; /* Span 3 rows of parent */ } /* Now children align across all cards */ .card h3 { /* All titles in row 1 */ } .card p { /* All content in row 2 */ } .card button { /* All buttons in row 3 - perfectly aligned! */ }

Example

<div class="grid"> <article class="card"> <h3>Short Title</h3> <p>Brief content.</p> <button>Action</button> </article> <article class="card"> <h3>Much Longer Title That Wraps</h3> <p>Longer content that takes more space.</p> <button>Action</button> </article> <article class="card"> <h3>Medium Title</h3> <p>Medium content.</p> <button>Action</button> </article> </div>

Result: Perfect Alignment

All buttons now align horizontally thanks to subgrid!

Subgrid on Columns

While subgrid is often used for row alignment, you can also use it for columns. This is particularly useful for form layouts where you want labels and inputs to align across multiple form sections.

Syntax

.form-grid { display: grid; grid-template-columns: 200px 1fr; gap: 1rem 2rem; } .form-row { display: grid; grid-template-columns: subgrid; /* Inherit columns! */ grid-column: span 2; /* Span both columns */ align-items: center; } /* Labels automatically in column 1, inputs in column 2 */

Example

<form class="form-grid"> <div class="form-row"> <label>Name</label> <input type="text"> </div> <div class="form-row"> <label>Email</label> <input type="email"> </div> <div class="form-row"> <label>Message</label> <textarea></textarea> </div> </form>

Result: Aligned Form

Subgrid on Both Axes

You can use subgrid on both rows and columns simultaneously. This creates a nested grid that inherits the entire track structure from its parent.

Syntax

.parent { display: grid; grid-template-columns: repeat(12, 1fr); grid-template-rows: repeat(4, 100px); gap: 1rem; } .child { display: grid; grid-template-rows: subgrid; grid-template-columns: subgrid; grid-row: span 2; grid-column: span 8; } /* Shorthand */ .child { grid: subgrid / subgrid; /* rows / columns */ }

Example: Dashboard Layout

Gap Inheritance and Override

By default, subgrids inherit the gap from their parent grid. However, you can override this gap in the subgrid if needed.

Syntax

.parent { display: grid; gap: 1rem; /* Parent gap */ } .child-inherits { grid-template-columns: subgrid; /* Uses parent's 1rem gap */ } .child-overrides { grid-template-columns: subgrid; gap: 0.5rem; /* Override with different gap */ }

Named Grid Lines with Subgrid

Named grid lines are inherited when using subgrid, allowing you to reference parent grid line names in the subgrid's children.

Syntax

.parent { display: grid; grid-template-columns: [start] 1fr [middle] 1fr [end]; } .child { display: grid; grid-template-columns: subgrid; grid-column: span 2; } /* Children can reference [start], [middle], [end] */ .grandchild { grid-column: start / middle; }

Practical Example: Product Card Grid

A common real-world use case: product cards with images, titles, descriptions, and prices that should all align perfectly across cards.

CSS

.product-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 1.5rem; } .product-card { display: grid; grid-template-rows: subgrid; grid-row: span 4; /* Image, title, description, price */ border: 1px solid #ddd; border-radius: 8px; overflow: hidden; } .product-card img { width: 100%; height: 200px; object-fit: cover; } .product-card .price { align-self: end; /* Stick to bottom of row */ font-size: 1.5rem; font-weight: 600; padding: 1rem; }

Result:

All prices align at the same height despite different content lengths!

When to Use Subgrid

Good Use Cases

  • Card grids - Aligning card elements (titles, content, buttons) across multiple cards
  • Forms - Perfect label-input alignment across rows
  • Data tables - Aligning nested table content with parent columns
  • Dashboards - Aligning widgets on a common grid system
  • Magazine layouts - Aligning nested content to parent grid lines

When NOT to Use Subgrid

  • When children should have independent grids with different structures
  • When you don't need alignment across sibling elements
  • Simple single-level grids (no nesting)

Important Subgrid Rules

1. Must Be a Grid Item

/* ✅ Works - child is a grid item */ .parent { display: grid; } .child { display: grid; grid-template-columns: subgrid; } /* ❌ Won't work - child isn't in a grid */ .parent { display: flex; } .child { grid-template-columns: subgrid; /* No effect! */ }

2. Must Specify Span

.item { grid-template-rows: subgrid; grid-row: span 3; /* Must specify how many rows to inherit */ }

3. Can Mix Subgrid and Regular Tracks

.item { grid-template-rows: subgrid; /* Inherit rows */ grid-template-columns: 1fr 2fr; /* Define own columns */ }

Comparison: Subgrid vs Nested Grid

Feature Nested Grid Subgrid
Track definition Child defines its own tracks Child inherits parent tracks
Alignment across siblings No automatic alignment Perfect alignment
Independence Fully independent Coupled to parent
Complexity More flexible, more complex Simpler for aligned layouts
Use case Different structure needed Need alignment across elements

Browser Support and Fallbacks

While subgrid is now supported in all modern browsers, you may want to provide fallbacks for older browsers.

Feature Detection

/* Fallback for browsers without subgrid */ .card { display: grid; grid-template-rows: auto 1fr auto; } /* Enhanced version with subgrid */ @supports (grid-template-rows: subgrid) { .card { grid-template-rows: subgrid; grid-row: span 3; } }

Key Takeaways