CSS Grid in 2026: Subgrid Is Everywhere — Here's How to Actually Use It
CSS Subgrid reached full cross-browser support in 2023 and is changing how developers build complex layouts. This guide covers the Grid fundamentals you need, how Subgrid solves the alignment problem, and when Grid beats Flexbox.

This article is currently only available in English. A Français translation is coming soon.

CSS Grid received its most significant upgrade since launch when Subgrid shipped in all major browsers — Chrome 117 (August 2023) was the last holdout after Firefox (2019) and Safari (2022). As of 2026, Subgrid is supported by over 94% of global browser traffic according to Can I Use. If you learned Grid before 2023, there is a meaningful addition to revisit.
This guide covers the Grid fundamentals that most tutorials skip, the Subgrid pattern that solves the most common layout problem, and a clear answer to "Grid vs Flexbox."
The fundamental mental model: rows AND columns simultaneously
Flexbox is one-dimensional — it arranges items along a single axis (row or column). Grid is two-dimensional — it creates rows and columns simultaneously and lets you place items anywhere in the resulting matrix.
.container {
display: grid;
grid-template-columns: 1fr 2fr 1fr; /* 3 columns, middle is twice as wide */
grid-template-rows: auto 400px auto; /* 3 rows, middle is fixed height */
gap: 24px;
}
1fr is a fraction unit — it takes "1 share of the available space." Three columns of 1fr 2fr 1fr distribute space in a 1:2:1 ratio. This is different from percentage widths because fr accounts for gaps automatically.
Build and preview grid layouts in real time at the Stax CSS Grid Generator.
Placing items on the grid
By default, grid items flow automatically into the next available cell. You can override this with explicit placement:
.hero {
grid-column: 1 / -1; /* Span from first column line to last */
grid-row: 1 / 2;
}
.sidebar {
grid-column: 3 / 4;
grid-row: 2 / 4; /* Span two rows */
}
Line numbers start at 1 for the left/top edge and -1 for the right/bottom edge. grid-column: 1 / -1 spans the full width regardless of how many columns exist — useful for responsive layouts where the column count changes.
Named areas make placement self-documenting:
.container {
grid-template-areas:
"header header header"
"sidebar main main"
"footer footer footer";
}
header { grid-area: header; }
.sidebar { grid-area: sidebar; }
main { grid-area: main; }
footer { grid-area: footer; }
The repeat() and minmax() functions
These two functions handle responsive column definitions without media queries:
/* Auto-fill as many columns as fit, minimum 200px each */
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
auto-fill creates as many columns as will fit. minmax(200px, 1fr) means each column is at least 200px but grows to fill available space. On a 900px container with 24px gaps: 4 columns of ~204px each. Resize to 600px: 3 columns. Resize to 250px: 1 column. Zero media queries.
auto-fit (vs auto-fill) collapses empty tracks — useful when you have fewer items than columns would allow and want them to expand rather than leave empty columns.
The problem Subgrid solves
Before Subgrid, every grid item was its own independent grid. If you had a card grid and wanted the card titles and buttons to align across cards of different content lengths — the classic "align baselines across independent items" problem — you had JavaScript workarounds or fixed heights.
The problem:
<div class="card-grid">
<article class="card">
<h2>Short title</h2>
<p>One line of text.</p>
<button>Read more</button>
</article>
<article class="card">
<h2>A much longer title that wraps to two lines</h2>
<p>Three lines of content that push the button down further than the neighbouring card.</p>
<button>Read more</button>
</article>
</div>
Without Subgrid, the two buttons sit at different heights. With Subgrid:
.card-grid {
display: grid;
grid-template-rows: auto auto auto; /* title, content, button rows */
gap: 16px;
}
.card {
display: grid;
grid-row: span 3; /* Each card spans 3 parent rows */
grid-template-rows: subgrid; /* Inherit the parent's row tracks */
}
Now all cards share the same row tracks. The tallest title defines the title row height for every card. The tallest content block defines the content row. Every "Read more" button aligns perfectly — no JavaScript, no fixed heights, no hacks.
This is the pattern Subgrid was designed for and it is now production-ready across all major browsers.
Grid vs Flexbox: the actual decision
The "Grid vs Flexbox" framing is largely a false choice — they solve different problems and work well together. But there are genuine preference cases:
| Use case | Better choice | Why |
|---|---|---|
| Page-level layout (header, sidebar, main, footer) | Grid | 2D placement |
| Card grid with alignment across cards | Grid + Subgrid | Row/column alignment |
| Navigation bar (items in a row) | Flexbox | 1D, spacing between items |
| Form fields (label + input pairs) | Grid | Column alignment |
| Button group | Flexbox | 1D wrapping |
| Masonry/Pinterest layout | Grid (grid-template-rows: masonry) |
CSS masonry (Firefox + Chrome flag in 2026) |
| Centering a single element | Either | display: grid; place-items: center or Flexbox |
| Component internals (icon + text) | Flexbox | Simple 1D alignment |
| Holy Grail layout | Grid | Simpler than Flexbox equivalent |
The practical rule: use Grid when you're thinking about rows and columns simultaneously. Use Flexbox when you're thinking about a single axis with wrapping.
See Flexbox patterns at the Stax CSS Flexbox Playground.
The gap property: consistent spacing without margin hacks
Before Grid and Flexbox, consistent spacing required margin tricks — margin-right on all items except the last (:last-child { margin-right: 0 }), or negative-margin wrappers. Both are fragile.
gap (formerly grid-gap) adds space between grid cells or flex items without outer margin:
.container {
gap: 24px; /* Same gap in all directions */
gap: 16px 24px; /* row-gap column-gap */
}
gap is now supported in both Grid and Flexbox, and in multi-column layout. It is the correct way to add consistent spacing in modern CSS.
Practical patterns to copy
Full-bleed layout with content column:
.page {
display: grid;
grid-template-columns:
minmax(16px, 1fr) minmax(auto, 720px) minmax(16px, 1fr);
}
.full-bleed { grid-column: 1 / -1; }
.content { grid-column: 2; }
12-column responsive grid:
.grid {
display: grid;
grid-template-columns: repeat(12, 1fr);
gap: 24px;
}
.col-4 { grid-column: span 4; }
.col-8 { grid-column: span 8; }
Auto-responsive card grid:
.cards {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 20px;
}
By Harshil Shah, developer and founder at Stax Tools. Browser support figures sourced from Can I Use (caniuse.com) as of May 2026.
Sources & methodology
- MDN Web Docs — CSS Grid Layout, developer.mozilla.org
- MDN Web Docs — Subgrid, developer.mozilla.org/en-US/docs/Web/CSS/CSS_grid_layout/Subgrid
- Can I Use — CSS Subgrid support table, caniuse.com/css-subgrid (accessed May 2026)
- CSS Specification — CSS Grid Layout Module Level 2, w3.org/TR/css-grid-2

Harshil
Developer & Founder, stax.tools
Harshil is the developer behind stax.tools, building privacy-first tools that run entirely in your browser.
More by Harshil →Found this useful?
Browse 235+ free privacy-first tools — no login, no uploads, instant results.