CSS Grid
Table of Contents
- Rows and Columns Together
- Defining Columns and Rows
- The fr Unit, repeat(), and gap
- Placing Items
- Named Areas: Draw Your Layout
- Responsive Grids Without Media Queries
- Alignment in Grid
- Grid or Flexbox?
- Recipe: Page Layout and Gallery
- Try It Yourself
1. Rows and Columns Together
Flexbox arranges items along one line. CSS Grid arranges them in two dimensions — rows and columns at once, like a spreadsheet or a newspaper layout. Reach for it when you want to line things up in both directions.
As with Flexbox, it starts with the parent:
.gallery {
display: grid;
}
The parent becomes a grid container, and its direct children become grid items. On its own this changes little — you also have to describe the tracks (the columns and rows).
2. Defining Columns and Rows
grid-template-columns lists the width of each column, and
grid-template-rows lists the height of each row:
.layout {
display: grid;
grid-template-columns: 200px 1fr 1fr;
}
That makes three columns: one fixed at 200px, and two sharing the rest. Children fill the cells from left to right, then start a new row when the columns run out. Rows are created automatically at the height of their content, so you often only need to define columns.
200px 1fr 1fr
┌───────┬──────────────┬──────────────┐
│ 1 │ 2 │ 3 │ row 1
├───────┼──────────────┼──────────────┤
│ 4 │ 5 │ 6 │ row 2
└───────┴──────────────┴──────────────┘
3. The fr Unit, repeat(), and gap
The fr unit is a fraction of the free space in the grid. It's
Grid's version of flex: 1:
| Declaration | Result |
|---|---|
1fr 1fr 1fr | Three equal columns |
1fr 2fr | Two columns; the second is twice as wide |
200px 1fr | A fixed sidebar and a flexible main column |
repeat() saves typing:
grid-template-columns: repeat(3, 1fr); /* same as 1fr 1fr 1fr */
gap adds space between rows and columns, exactly as in Flexbox:
.gallery {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
}
Three equal columns with a gap between, in four lines. You can also set
row-gap and column-gap separately.
4. Placing Items
Normally items are placed automatically, in order. When you want one to span more than one cell, tell it:
.featured {
grid-column: span 2; /* take up two columns */
}
.hero {
grid-column: 1 / -1; /* from first line to the last line */
}
Grid lines are numbered from 1, and -1 is the last line, so
1 / -1 means "the full width". grid-row: span 2 does the same
downwards. You can also name exact lines — grid-column: 2 / 4 starts
at line 2 and ends at line 4.
5. Named Areas: Draw Your Layout
Grid's most readable feature lets you draw the layout as text with
grid-template-areas:
.page {
display: grid;
grid-template-columns: 14rem 1fr;
grid-template-areas:
"header header"
"sidebar main"
"footer footer";
gap: 1rem;
min-height: 100vh;
}
.page > header { grid-area: header; }
.page > aside { grid-area: sidebar; }
.page > main { grid-area: main; }
.page > footer { grid-area: footer; }
The strings are rows, and each word is a cell. Repeating a name spans the cells. The picture in the CSS matches the picture on screen:
┌──────────────────────────────┐
│ header │
├──────────┬───────────────────┤
│ sidebar │ main │
├──────────┴───────────────────┤
│ footer │
└──────────────────────────────┘
To rearrange for a phone, you only redefine the template (see chapter 11) — the HTML stays untouched, and still reads in a sensible order for screen readers.
6. Responsive Grids Without Media Queries
The best-known Grid pattern is a gallery that sets its own column count based on the available width:
.gallery {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
gap: 1rem;
}
Read it as: "make as many columns as will fit, each at least 14rem and at most an equal share of the space."
minmax(14rem, 1fr)is a column that is never narrower than 14rem but can grow.auto-fitcreates as many of them as fit in the row.
On a wide screen: four columns. On a tablet: two. On a phone: one. And unlike the Flexbox version in chapter 9, every row has the same column widths, so the last row never stretches. Reach for this one first when you build any list of cards.
Tip: if the grid should never use too little room on tiny screens, write
minmax(min(14rem, 100%), 1fr) so a column can shrink below 14rem when
the container is narrower.
7. Alignment in Grid
The alignment properties from Flexbox work here too, with the same names:
| Property | Where | Does |
|---|---|---|
justify-items | Container | Aligns items horizontally inside their cell |
align-items | Container | Aligns items vertically inside their cell |
place-items: center | Container | Shorthand: both at once |
justify-content, align-content | Container | Places the whole grid inside the container |
justify-self, align-self | One item | Overrides it for one item |
Centering something in both directions is display: grid; place-items: center; — even shorter than Flexbox's three lines.
8. Grid or Flexbox?
They aren't competitors; most pages use both. A rule that works:
| Use… | When… |
|---|---|
| Flexbox | You're arranging items in one direction and the content should decide the size: navbars, button groups, toolbars, a card's inner layout |
| Grid | You're laying out the page or a region in rows and columns, and the layout should decide the size: page templates, galleries, dashboards |
Another way to ask: "do I care about alignment across rows?" If yes — columns that line up from one row to the next — use Grid. If you only care about spreading items along one line, use Flexbox.
You can nest them freely: a Grid page layout holds a <header> that's a
Flexbox navbar, and a Grid gallery of cards where each card uses Flexbox
to pin its button to the bottom.
9. Recipe: Page Layout and Gallery
Combine the pieces. In index.html, wrap the projects in a gallery:
<section id="projects">
<h2>Projects</h2>
<div class="gallery">
<article class="card">…</article>
<article class="card">…</article>
<article class="card">…</article>
</div>
</section>
.gallery {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
gap: 1rem;
}
.card {
display: flex;
flex-direction: column;
}
.card .button {
margin-top: auto; /* pushes the button to the bottom of every card */
}
That's both tools in one component: Grid for the gallery, Flexbox inside each card so the buttons align at the bottom regardless of how much text each card has.
For the About page, use named areas for a two-column layout with the photo beside the text:
.about {
display: grid;
grid-template-columns: 1fr;
gap: 1.5rem;
}
@media (min-width: 40rem) {
.about {
grid-template-columns: 12rem 1fr;
align-items: start;
}
}
The @media rule is the topic of the next chapter. For now, trust that
it says "when the screen is at least 40rem wide, use two columns."
10. Try It Yourself
- Equal columns. Make a grid with 6 boxes and
repeat(3, 1fr). Add agap. Then change it to1fr 2fr 1fr. - Inspect it. In DevTools, click the
gridbadge next to the container to show the overlay with numbered lines. Which line is the end of the second column? - Span. Make the first box
grid-column: span 2. What happens to the rest? Then trygrid-row: span 2. - Draw a page. Build the header/sidebar/main/footer layout from
section 5 with
grid-template-areason a scratch page. - Build the gallery. Add the
auto-fitgallery to your projects. Resize the window slowly, and count the columns at each width. - Compare with Flexbox. Make the same cards with the Flexbox version from chapter 9 and with Grid. Add a 5th card. Which handles the last row better?
- Center anything. Use
display: grid; place-items: center;to center a message in a full-heightdiv.
Commit. You have all the tools; the last chapter is about making the page work well on every screen, and then putting it on the internet.
Buy Me a Coffee
Found this tutorial helpful? Consider buying me a coffee to support more free content!