Build a full page layout and a responsive gallery with CSS Grid, template areas and the fr unit.
Why this matters
Flexbox arranges items along one line. Many layouts are two-dimensional: a header across the top, a sidebar and main area side by side, a footer at the bottom, or a gallery of tiles in rows and columns. CSS Grid is built for that. It lets you describe the whole layout on the parent, in a way that reads almost like a drawing.
The core idea: tracks on the container
.gallery {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 1rem;
}
display: gridmakes the element a grid container; its direct children become grid items.grid-template-columnsdefines the column tracks. Here: three equal columns.- Items flow into the cells automatically, left to right, then onto the next row.
gapsets the space between rows and columns.
The fr unit
fr means "a fraction of the remaining space". After fixed tracks and gaps are subtracted, the leftover space is shared in proportion:
grid-template-columns: 200px 1fr; /* fixed sidebar, flexible main area */
grid-template-columns: 2fr 1fr; /* main area twice as wide as the side */
grid-template-columns: repeat(4, 1fr); /* four equal columns */
repeat(4, 1fr) is shorthand for 1fr 1fr 1fr 1fr.
Template areas: drawing the layout
For page layouts, name the regions and draw them as a map:
.page {
display: grid;
grid-template-columns: 200px 1fr;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"header header"
"sidebar main"
"footer footer";
min-height: 100vh;
}
.site-header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.content { grid-area: main; }
.site-footer { grid-area: footer; }
- Each quoted string is one row; each word is one column cell.
- Repeating a name (
"header header") makes that area span both columns. grid-template-rows: auto 1fr autosizes the header and footer to their content and gives the middle row the remaining height, so withmin-height: 100vhthe footer sits at the bottom of the screen even on a short page.- Each item claims its area with
grid-area.
Areas must form rectangles; an L-shaped area is invalid and the whole template is ignored. A . in the map leaves a cell empty.
Placing items by line number
Grid lines are numbered from 1 at the start edge. You can place an item across lines directly:
.feature {
grid-column: 1 / 3; /* from line 1 to line 3: spans two columns */
grid-row: 1; /* first row */
}
.banner {
grid-column: 1 / -1; /* -1 is the last line: full width */
}
Template areas are easier to read for whole pages; line numbers are handy for one special item inside a gallery.
Worked example: a gallery with no media queries
.gallery {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 1rem;
}
Read it from the inside out:
minmax(150px, 1fr): each column is at least 150px and at most an equal share of the space.repeat(auto-fit, ...): create as many columns as fit.
On a 1,000px-wide area you get six columns; on a 350px phone you get two; at 300px, one. The tiles reflow by themselves. This single line is one of the most useful patterns in modern CSS.
Grid or Flexbox?
| Use Grid when | Use Flexbox when |
|---|---|
| you control rows and columns | items flow in one row or column |
| the layout comes first and content fills it | the content size comes first |
| page skeletons, galleries, dashboards, forms in columns | nav bars, toolbars, button groups, centring |
They work together: a grid page whose header uses Flexbox for its nav is completely normal.
Inspecting a grid
In Chrome, Edge and Firefox developer tools, a small grid badge appears next to grid containers in the Elements panel. Click it to overlay the line numbers, track sizes and area names on the page. It is the quickest way to see why an item landed in the wrong cell.
Common mistakes
- Setting
display: gridon the items instead of the container. - A typo in an area name, so the item falls into the next free cell instead.
- Non-rectangular template areas, which make the browser ignore the whole template.
- Changing the visual order with grid placement so it no longer matches the HTML order, which confuses keyboard and screen reader users.
- Fixed pixel columns everywhere (
300px 300px 300px), which overflow on phones; usefrandminmax().
Quick recap
display: gridplusgrid-template-columns(and rows) define tracks;gapspaces them.frshares the remaining space;repeat()saves typing.grid-template-areasdraws a page layout; items join withgrid-area.repeat(auto-fit, minmax(150px, 1fr))gives a gallery that adapts with no media queries.
Try it
Open the Do tab and build a header, sidebar, main and footer page layout with template areas, plus a self-adjusting gallery.