If Flexbox is a "one-dimensional" arrangement tool, then Grid is a truly "two-dimensional" layout system — it controls rows and columns at the same time, letting us describe complex newspaper-style layouts with pure CSS for the first time, without nesting divs to fake it.
How Grid Complements Flexbox
Flexbox
Grid
Dimensions
One-dimensional (a row or a column)
Two-dimensional (rows and columns at once)
Driving model
Content-driven; sizes expand from content
Layout-driven; define tracks first, then place content
In practice the two are not mutually exclusive: the common approach is to build the page-level skeleton with Grid, then use Flexbox for the one-dimensional arrangement inside each block of that skeleton.
grid-template-columns / grid-template-rows define "tracks" with a space-separated list of lengths, each value being the size of one column or row. Between tracks, "grid lines" form naturally, numbered starting from 1; repeat() can also simplify repeated tracks:
fr (fraction) is a flexible unit exclusive to Grid, meaning "a share of the remaining space". It works on the same idea as flex-grow but is more flexible — it can be mixed with fixed lengths:
.layout {
grid-template-columns: 200px 1fr 2fr;
/* the first column is fixed at 200px; remaining space is split 1:2 between columns 2 and 3 */
}
Placing Items
Items can use grid line numbers to precisely specify where they start and end:
.hero {
grid-column: 1 / 3; /* from line 1 to line 3, spanning 2 columns */grid-row: 1 / 2;
}
/* the span keyword: spans N tracks without caring about start/end numbers */.wide { grid-column: span 2; }
Preview: the second item spans two columns
1
span 2
3
4
grid-template-areas: Named Areas
Dividing the grid into semantically named areas is Grid's most readable feature — the layout structure is "drawn" in the CSS, instantly clear:
TipEach row of strings must have as many words as there are columns; consecutive dots . leave an empty area that is assigned to no item.
auto-fit / auto-fill / minmax: Adaptive Grids
This is Grid's most powerful combination, achieving a card grid that is "responsive without writing media queries" — the number of columns is decided automatically from the container's width.
minmax(200px, 1fr) means each column is at least 200px and at most an equal share of the remaining space; auto-fit automatically works out how many columns fit and stretches existing columns to fill the whole row; auto-fill keeps the positions of "invisible" empty tracks, so columns do not get stretched too wide. The difference only shows up when there is not enough leftover space for another column.
When there is room for more columns
auto-fit
Existing columns stretch to fill the row; no empty tracks are left
auto-fill
Positions of potential empty tracks are kept; existing columns are not stretched extra
The Implicit Grid
When the number of items exceeds the tracks defined by grid-template-*, the browser automatically generates "implicit tracks" to hold the extra content. Use grid-auto-rows / grid-auto-columns to control the size of these implicit tracks, and grid-auto-flow: dense makes the placement algorithm actively backfill gaps it skipped earlier.