Learn CSS · Lesson 7 of 7 · 10 min
CSS Grid
Here is the leap that flexbox cannot make: Grid lays things out in two dimensions at once, controlling rows and columns together instead of one line at a time. When you want a real layout, a page split into regions, a card wall, a magazine spread, Grid is the most powerful tool CSS has.
The grid container
Grid is opt-in, just like flexbox. You set display: grid on a parent
element, and its direct children instantly become grid items that you can
arrange on a row-and-column matrix. The parent is the grid container; everything you
do happens through it.
.gallery {
display: grid; /* this element is now a grid */
}
/* every direct child is a grid item you can place */ On its own that single declaration does very little, because you have not told the grid what its columns are yet. That is the next, and most important, step.
Defining tracks with grid-template-columns and the fr unit
A grid is made of tracks: the columns and rows themselves. You declare the columns
with grid-template-columns, listing one size per column. The number of values you write
is the number of columns you get.
.gallery {
display: grid;
grid-template-columns: 200px 200px 200px; /* three fixed columns */
} Fixed pixels rarely flex well, so Grid adds a unit built for this job: fr, the
fraction. One fr means "one share of the leftover space." Three equal
columns become 1fr 1fr 1fr, and they share the container's width evenly no matter how wide
it is. Mix them to weight columns: 2fr 1fr makes the first column twice as wide as the
second.
.gallery {
display: grid;
grid-template-columns: 1fr 1fr 1fr; /* three equal, fluid columns */
}
.sidebar-layout {
display: grid;
grid-template-columns: 240px 1fr; /* fixed sidebar, fluid main */
} Rows work the same way with grid-template-rows, but you often leave rows alone: Grid
creates rows automatically as items wrap onto new lines, sizing each to its content.
gap: spacing without margins
To put space between tracks, use gap on the container. One property handles the gutters
between every row and column, and unlike margins it never collapses and never adds an unwanted edge on
the outside of the grid. Use row-gap and column-gap when you want them
different.
.gallery {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 16px; /* 16px between every cell, evenly */
} Placing and spanning items
Here is where the second dimension earns its keep. By default items flow into cells in order, one per
cell, left to right and top to bottom. But any item can be told to span across
multiple columns or rows with grid-column and grid-row. The friendliest form
is the span keyword, which simply says how many tracks to cover.
.feature {
grid-column: span 2; /* this cell is two columns wide */
}
.tall {
grid-row: span 2; /* this cell is two rows tall */
} That one line is the whole reason Grid exists. A child can claim a 2 by 1 region while its siblings fill in around it, and the layout stays a clean matrix. Watch the highlighted cell below break the even rhythm by spanning two columns:
Notice that you never touched the other cells. They simply reflowed to make room, which is the part that is genuinely hard to do with floats or even flexbox.
repeat(), minmax(), and responsive grids
Writing 1fr 1fr 1fr 1fr gets old fast, so Grid gives you repeat():
repeat(3, 1fr) means "three columns of 1fr." Pair it with minmax(min, max),
which sets a floor and a ceiling for a track, for example minmax(120px, 1fr) reads
"at least 120px, but grow to share leftover space."
Combine those two with the auto-fit keyword and you get the single most useful line in all
of layout, a grid that reflows by itself with no media queries:
.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
gap: 12px;
} That tells the browser: "fit as many 120px-or-wider columns as you can, then stretch them to fill the row." Resize the page and the column count rises and falls on its own. Drag the box below narrower (or view it on your phone) and watch the cells rewrap:
One declaration replaces several breakpoints. That is responsive design with almost no media queries, and it is the trick behind most modern card walls.
Grid vs Flexbox
These two are partners, not rivals. The honest rule of thumb is about dimensions:
- Flexbox is one-dimensional. It lays content out along a single line, a row or a column, and is unbeatable for things that should sit in a line and flex to fit: a nav bar, a row of buttons, a card's inner header. Wrapping items size themselves to their content.
- Grid is two-dimensional. It controls rows and columns together, so cells line up in both directions at once. Reach for it for the overall page skeleton and any layout where alignment across rows matters.
In practice you use them together: Grid to place the big regions of the page, then flexbox inside individual cells to arrange their contents. Neither replaces the other. If you want the one-dimensional half of the story, see the flexbox lesson, and for a full build, follow our tutorial on the bento-box layout.
Practice
Two minutes each, and each one locks in a single idea. Use a blank CodePen, your browser's DevTools, or one of our tools to experiment:
- Make a container with six children. Give it
display: grid,grid-template-columns: repeat(3, 1fr)andgap: 12px. Confirm you get a tidy 3 by 2 grid with even gutters. - On the first child, add
grid-column: span 2. Watch it grow to two columns wide while the others reflow around it. Then trygrid-row: span 2on a different cell. - Swap the columns for
repeat(auto-fit, minmax(120px, 1fr)), remove any fixed column count, and drag your browser window from wide to narrow. Count how the columns rise and fall with zero media queries.
The mental model to keep
display: gridon the parent makes its direct children grid items.grid-template-columnsdefines the columns; thefrunit shares leftover space.gapspaces the tracks and never collapses, unlike margins.grid-column: span n(andgrid-row) let one cell cover multiple tracks.repeat(auto-fit, minmax(min, 1fr))builds a responsive grid with no media queries.- Grid is two-dimensional, flexbox is one-dimensional; use them together.
That is CSS Grid. It is the backbone of nearly every modern page layout, so once spanning and
auto-fit feel natural, you can build almost any arrangement you can picture.