CSS Grid is the only native CSS layout system built for two dimensions at once, and once you learn grid-template-areas, you'll stop writing media queries for layouts that shouldn't need them.
CSS Grid lets you define rows and columns explicitly on a container, then place children into that structure by line number, area name, or automatic flow — giving you precise control over both axes simultaneously, something flexbox was never designed to do. If your layout needs items to align in both rows and columns at once, Grid is almost always the right call.
Why Grid Matters (and When to Skip It)
Before Grid, two-dimensional layouts meant nested flexbox containers, floats, or frameworks like Bootstrap's 12-column system bolted on top of CSS that wasn't built for it. Grid does it natively, with less markup and fewer wrapper divs.
Skip it for genuinely one-dimensional content — a single row of buttons or a vertical list doesn't need Grid's overhead. That's flexbox's job. Grid earns its place the moment you're aligning content across both axes: dashboards, image galleries, page shells with header/sidebar/footer.
Getting Started with Grid
Define columns and rows, then place children by area name — this single pattern replaces most layout media queries:
.page {
display: grid;
grid-template-columns: 240px 1fr;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"sidebar header"
"sidebar main"
"sidebar footer";
min-height: 100vh;
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.footer { grid-area: footer; }
Rearranging the layout for mobile means redefining grid-template-areas inside a media query — no HTML changes, no reordering markup.
Core Grid Concepts Every Developer Should Know
fr units distribute remaining space proportionally. grid-template-columns: 1fr 2fr gives the second column exactly twice the width of the first, and both adjust automatically as the container resizes.
auto-fit and auto-fill build responsive grids without a single media query:
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap: 16px;
}
This creates as many 240px-minimum columns as fit, stretching them to fill leftover space. auto-fill does the same but keeps empty tracks instead of collapsing them — the difference only shows when there are fewer items than columns that would fit.
Implicit vs. explicit grid. Anything you define with grid-template-columns/rows is the explicit grid. Content that overflows it creates implicit rows/columns automatically, sized by grid-auto-rows/grid-auto-columns.
grid-column: span 2 lets individual items break the pattern — useful for a "featured" card in an otherwise uniform grid, without restructuring the whole layout.
Common Grid Mistakes and How to Fix Them
Mistake 1: using fixed pixel columns instead of minmax() with auto-fit. A grid with grid-template-columns: 300px 300px 300px breaks the moment the container is narrower than 900px. Fix: use repeat(auto-fit, minmax(300px, 1fr)) so columns collapse gracefully.
Mistake 2: forgetting gap works in Grid too. Some developers still reach for margin hacks on grid children out of flexbox habit. gap (or row-gap/column-gap) is fully supported and is the correct way to space grid items.
Mistake 3: nesting Grid inside Grid unnecessarily. For most layouts, one grid with well-named template areas is more maintainable than three nested grids each solving a small piece. Fix: reach for grid-template-areas before nesting.
When Should You Use Grid Instead of Flexbox?
Use Grid when content needs to align across both rows and columns — image galleries, dashboards, page shells with a sidebar. Use flexbox for a single row or column of items, like a toolbar or a tag list. Many real layouts use both: Grid for the page shell, flexbox for content inside individual grid cells.
Grid in Production
grid-template-areas is the most underused Grid feature and the highest-leverage one for readability — a layout defined as a visual ASCII map in CSS is dramatically easier for a teammate to understand than a stack of grid-column: 3 / 5 line-number declarations. For component libraries, auto-fit + minmax() is worth defaulting to for any card grid, since it removes an entire category of responsive breakpoint bugs.
Next responsive grid you build, reach for repeat(auto-fit, minmax(...)) before writing a single media query — it solves the problem the media query was going to solve, with less code.