CSS Grid is the most powerful layout system in CSS. Unlike Flexbox (which handles one dimension at a time), Grid gives you simultaneous control over rows and columns. Once you learn the core concepts, you can build any layout — from a 12-column magazine grid to a complex dashboard — in a handful of lines.
This cheat sheet covers every property with working code, the six most common patterns, and the mistakes developers hit most often.
How Grid works
There are two players: the grid container (the parent) and grid items (the direct children).
<div class="container"> <!-- grid container -->
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
</div>
.container {
display: grid;
grid-template-columns: 1fr 1fr 1fr; /* 3 equal columns */
gap: 16px;
}
Grid introduces an invisible set of lines (numbered from 1). Items sit in cells formed where column lines and row lines cross. You can place items explicitly by line number, or let Grid auto-place them.
Container properties
grid-template-columns / grid-template-rows
Define the track sizes (columns and rows).
/* Three equal columns */
grid-template-columns: 1fr 1fr 1fr;
/* Mixed: fixed + flexible */
grid-template-columns: 250px 1fr 1fr;
/* Shorthand with repeat() */
grid-template-columns: repeat(3, 1fr);
/* Three rows: auto height */
grid-template-rows: auto auto auto;
/* Named sizes */
grid-template-rows: 60px 1fr 40px; /* header content footer */
The fr unit means fraction of the available free space. 1fr 2fr gives one column twice the width of the other.
grid-template-areas
Visually map your layout using named areas — the most readable way to define complex layouts.
.container {
display: grid;
grid-template-columns: 200px 1fr;
grid-template-rows: 60px 1fr 50px;
grid-template-areas:
"header header"
"sidebar content"
"footer footer";
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.content { grid-area: content; }
.footer { grid-area: footer; }
A dot . marks an empty cell. Named areas must form a rectangle — irregular shapes cause an error.
gap / column-gap / row-gap
Spacing between tracks (not outer edges).
gap: 16px; /* row and column gap both 16px */
gap: 24px 16px; /* row-gap 24px, column-gap 16px */
row-gap: 24px; /* rows only */
column-gap: 16px; /* columns only */
gap replaces the older grid-gap — use the new name.
grid-auto-flow
Controls how auto-placed items fill the grid.
| Value | Behaviour |
|---|---|
row (default) |
Fill row by row, add rows as needed |
column |
Fill column by column, add columns as needed |
dense |
Backfill holes with smaller items |
row dense |
Row-first + backfill |
column dense |
Column-first + backfill |
grid-auto-flow: dense; /* useful for masonry-style grids */
grid-auto-columns / grid-auto-rows
Size for implicitly created tracks (when items overflow your defined template).
grid-auto-rows: 200px; /* each implicit row is 200px */
grid-auto-rows: minmax(100px, auto); /* at least 100px, grows with content */
justify-items / align-items
Align all items inside their cells.
| Property | Axis | Default |
|---|---|---|
justify-items |
Inline (horizontal) | stretch |
align-items |
Block (vertical) | stretch |
justify-items: start | end | center | stretch;
align-items: start | end | center | stretch;
/* Shorthand */
place-items: center; /* center on both axes */
place-items: start end; /* align-items start, justify-items end */
justify-content / align-content
Align the whole grid inside the container when the grid is smaller than the container.
justify-content: start | end | center | stretch | space-between | space-around | space-evenly;
align-content: start | end | center | stretch | space-between | space-around | space-evenly;
/* Shorthand */
place-content: center;
Item properties
grid-column / grid-row
Place an item by specifying which grid lines it spans.
/* span from line 1 to line 3 (2 columns wide) */
grid-column: 1 / 3;
/* shorthand: start-line / span N */
grid-column: 1 / span 2;
/* span to the end */
grid-column: 2 / -1;
/* rows */
grid-row: 1 / 3; /* rows 1 and 2 */
grid-row: 2 / span 3; /* rows 2, 3, and 4 */
Negative line numbers count from the end of the explicit grid. -1 is always the last line.
grid-area
Shorthand for row-start / column-start / row-end / column-end — or a named area reference.
/* Place by line numbers: row-start / col-start / row-end / col-end */
grid-area: 1 / 2 / 3 / 4;
/* Reference a named area from grid-template-areas */
grid-area: header;
justify-self / align-self
Override alignment for a single item.
.item {
justify-self: center; /* override justify-items for this item */
align-self: end; /* override align-items for this item */
/* Shorthand */
place-self: center end;
}
order
Change the visual order of items without changing the DOM. Items with lower order appear first.
.first { order: -1; } /* moved before default (0) items */
.last { order: 1; } /* moved after default items */
⚠
orderaffects visual order only — keyboard/screen-reader order follows the DOM. Don't use it for meaningful content reordering.
Quick reference: property summary
| Property | Where | What it does |
|---|---|---|
grid-template-columns |
Container | Define column tracks |
grid-template-rows |
Container | Define row tracks |
grid-template-areas |
Container | Named-area layout map |
gap / row-gap / column-gap |
Container | Space between tracks |
grid-auto-flow |
Container | Auto-placement direction |
grid-auto-columns |
Container | Implicit column size |
grid-auto-rows |
Container | Implicit row size |
justify-items |
Container | Align all items horizontally |
align-items |
Container | Align all items vertically |
justify-content |
Container | Align grid horizontally in container |
align-content |
Container | Align grid vertically in container |
grid-column |
Item | Span columns by line number |
grid-row |
Item | Span rows by line number |
grid-area |
Item | Shorthand placement or named area |
justify-self |
Item | Override horizontal alignment |
align-self |
Item | Override vertical alignment |
order |
Item | Visual ordering |
6 common patterns
1. Responsive card grid (no media queries)
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 24px;
}
auto-fill creates as many columns as fit. minmax(280px, 1fr) ensures each card is at least 280px but stretches to fill space. Zero media queries needed.
2. Holy grail layout (header, sidebar, content, footer)
.page {
display: grid;
grid-template-columns: 220px 1fr;
grid-template-rows: 60px 1fr 50px;
grid-template-areas:
"header header"
"sidebar main"
"footer footer";
min-height: 100vh;
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.footer { grid-area: footer; }
3. 12-column grid (Bootstrap-style)
.row {
display: grid;
grid-template-columns: repeat(12, 1fr);
gap: 16px;
}
.col-4 { grid-column: span 4; }
.col-6 { grid-column: span 6; }
.col-12 { grid-column: span 12; }
4. Dashboard with fixed sidebar
.dashboard {
display: grid;
grid-template-columns: 260px 1fr;
grid-template-rows: 56px 1fr;
height: 100vh;
}
.topbar { grid-column: 1 / -1; } /* full width */
.sidebar { grid-row: 2; }
.content { grid-row: 2; overflow-y: auto; }
5. Centred hero (both axes)
.hero {
display: grid;
place-items: center;
height: 100vh;
}
place-items: center is the shortest way to centre a single child both horizontally and vertically.
6. Magazine / masonry-style grid
.magazine {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-auto-rows: 200px;
gap: 16px;
}
.featured {
grid-column: span 2;
grid-row: span 2;
}
Use grid-auto-flow: dense to fill gaps left by large items:
.magazine { grid-auto-flow: dense; }
6 common mistakes
1. Confusing fr with %
1fr uses free space after fixed tracks. % is a percentage of the container width.
/* This is fine — 250px sidebar + remaining space */
grid-template-columns: 250px 1fr;
/* This breaks when there's a gap — percentages include gap space */
grid-template-columns: 25% 75%; /* may overflow if gap > 0 */
Use fr for flexible tracks; % only when you explicitly need a percentage of the container.
2. Forgetting min-content trap with 1fr
By default, 1fr cannot shrink below the content's min-content size. This breaks equal columns.
/* Fix: override min-width so columns can actually be equal */
.item { min-width: 0; } /* or min-width: 0px */
3. auto-fill vs auto-fit
Both fill columns dynamically, but:
auto-fillkeeps empty columns (grid remains wide).auto-fitcollapses empty columns (tracks stretch to fill).
/* If you have 2 items in a 5-column grid: */
grid-template-columns: repeat(auto-fill, 100px); /* leaves 3 empty 100px columns */
grid-template-columns: repeat(auto-fit, 100px); /* 2 columns stretch to fill */
Use auto-fit with minmax() for truly responsive grids.
4. gap vs margin for spacing
gap only adds space between tracks, never on outer edges. Use padding on the container for outer spacing.
.grid {
display: grid;
gap: 16px;
padding: 16px; /* outer spacing — gap does not do this */
}
5. grid-template-areas must be rectangular
Every named area must form a solid rectangle. Irregular shapes throw an error.
/* ❌ Invalid — "header" is not rectangular */
grid-template-areas:
"header ."
". header";
/* ✅ Valid */
grid-template-areas:
"header header"
"sidebar content";
6. Implicit rows grow to fit content
If you don't define grid-template-rows or grid-auto-rows, implicit rows size to their content. This causes inconsistent heights.
/* Fix: set a minimum row height */
grid-auto-rows: minmax(120px, auto);
CSS Grid vs Flexbox
| Grid | Flexbox | |
|---|---|---|
| Dimensions | 2D (rows + columns) | 1D (row or column) |
| Best for | Page-level layout, complex grids | Component-level alignment |
| Item placement | Explicit by line/area | Sequential, flex-based |
| Overlap | Items can overlap via placement | Items don't overlap |
| Browser support | 97%+ | 99%+ |
Rule of thumb: use Grid for the outer page structure; use Flexbox for the inner components (nav items, button groups, form rows).
Frequently asked questions
Does CSS Grid work without grid-template-rows?
Yes. If you skip grid-template-rows, rows are sized implicitly using grid-auto-rows (default: auto, meaning content height). Define grid-auto-rows: minmax(100px, auto) for consistent card heights.
What is the fr unit?fr stands for fraction of the remaining free space. 1fr 2fr splits free space into thirds — one third goes to column 1, two thirds to column 2. Fixed tracks (px, rem) are subtracted first; fr divides what's left.
Can grid items overlap?
Yes — place two items at the same grid coordinates and use z-index to control stacking. This is useful for overlapping text on images or decorative elements.
How do I centre one item inside a grid cell?
Use place-self: center on the item, or place-items: center on the container to centre all items.
What's the difference between grid-template-columns and grid-auto-columns?grid-template-columns defines the explicit grid (the columns you declared). grid-auto-columns sizes any implicit columns created when items are placed outside the explicit grid.
How do I make a single column full-width in a multi-column grid?
.full-width {
grid-column: 1 / -1; /* span from first to last line */
}
-1 refers to the last line of the explicit grid, so this always spans all defined columns.