CSS Grid Tutorial
Getting Started with CSS Grid
CSS Grid is a two-dimensional layout system that controls both rows and columns simultaneously. It replaces float-based layouts, table hacks, and inline-block workarounds with a declarative model the browser handles natively.
To activate Grid, set display: grid on a container. Its direct children become grid items.
.grid-container {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
}
.grid-item {
/* Each item occupies one cell by default */
}
Only direct children participate in the grid. Nested elements need their own display: grid if you want sub-grid behavior.
grid-template-columns and grid-template-rows
These properties define the track structure — the columns and rows of your grid.
Fixed Sizes
.grid-container {
display: grid;
grid-template-columns: 200px 300px 200px;
grid-template-rows: 100px 400px;
}
Columns stay at exactly 200px, 300px, and 200px. Not responsive, but useful for fixed-width layouts.
Flexible Sizes with fr
The fr unit distributes remaining space proportionally:
.grid-container {
display: grid;
grid-template-columns: 1fr 2fr 1fr;
}
The middle column gets twice the space of each outer column. This is the most common pattern for responsive grids.
repeat() Notation
Save keystrokes with repeat():
/* Equivalent declarations */
grid-template-columns: 1fr 1fr 1fr 1fr;
grid-template-columns: repeat(4, 1fr);
/* With minmax */
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
Mixing Units
Combine fixed and flexible tracks in one declaration:
.grid-container {
display: grid;
grid-template-columns: 260px 1fr 1fr;
grid-template-rows: auto 1fr auto;
}
A fixed sidebar on the left, flexible content columns, and rows that size to content at the top and bottom.
grid-gap (Row and Column Gaps)
Gaps control spacing between tracks. They replace margin-based spacing and never apply before the first item or after the last.
.grid-container {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 24px; /* rows and columns */
row-gap: 16px; /* vertical only */
column-gap: 32px; /* horizontal only */
}
Gap values are subtracted from available space before fr units are calculated. With a 1000px container, three 1fr columns, and a 24px gap, each column gets (1000 - 48) / 3 = 317px.
grid-area and Named Areas
grid-template-areas is the most readable way to define complex layouts. You draw the layout with names instead of calculating line numbers:
.dashboard {
display: grid;
grid-template-columns: 240px 1fr 1fr;
grid-template-rows: 64px 1fr 1fr 48px;
grid-template-areas:
"nav nav nav"
"sidebar chart chart"
"sidebar table stats"
"footer footer footer";
gap: 16px;
}
.nav { grid-area: nav; }
.sidebar { grid-area: sidebar; }
.chart { grid-area: chart; }
.table { grid-area: table; }
.stats { grid-area: stats; }
.footer { grid-area: footer; }
A period (.) marks an empty cell. Named areas make the layout visible in the CSS itself, easy to rearrange for mobile, and simple for teams to understand.
Shorthand: grid-area with Line Numbers
You can also use grid-area as a shorthand for all four placement values:
.featured-item {
grid-area: 1 / 1 / 3 / 4;
/* row-start / column-start / row-end / column-end */
}
grid-auto-flow
When items outnumber explicit tracks, the browser creates implicit tracks. grid-auto-flow controls how items fill those tracks:
| Value | Behavior |
|---|---|
row (default) | Fills left to right, then wraps to next row |
column | Fills top to bottom, then moves to next column |
dense | Backfills gaps left by spanning items |
.gallery {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
grid-auto-flow: dense;
gap: 8px;
}
Use dense for image galleries where items have varying spans and you want compact layouts without empty gaps.
Practical Examples
Holy Grail Layout
The classic web layout — header, three-column body, and footer:
.holy-grail {
display: grid;
grid-template-columns: 200px 1fr 200px;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"header header header"
"left content right"
"footer footer footer";
min-height: 100vh;
}
All three columns maintain consistent height without JavaScript or table hacks.
Dashboard Layout
Asymmetrical panels with varying spans:
.dashboard {
display: grid;
grid-template-columns: 260px 1fr 1fr 1fr;
grid-template-rows: 56px 2fr 1fr;
grid-template-areas:
"toolbar toolbar toolbar toolbar"
"nav main main aside"
"nav widget1 widget2 aside";
gap: 12px;
}
The 2fr row gives the main area more vertical space than the widget row.
Photo Gallery
Responsive grid with featured items spanning multiple cells:
.gallery {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
grid-auto-rows: 200px;
grid-auto-flow: dense;
gap: 8px;
}
.gallery-item.featured {
grid-column: span 2;
grid-row: span 2;
}
The dense packing ensures smaller items fill gaps left by the featured images.
Spanning and Placement
Items can span multiple tracks using line numbers or the span keyword:
/* Span 2 columns */
.item {
grid-column: span 2;
}
/* Span from line 2 to line 4 */
.item {
grid-column: 2 / 4;
}
/* Span 2 columns starting from line 2 */
.item {
grid-column: 2 / span 2;
}
/* Full shorthand: row-start / col-start / row-end / col-end */
.item {
grid-area: 1 / 1 / 3 / 4;
}
Prefer span over raw line numbers when you do not need to target specific lines — it is more readable and resilient to track changes.
Alignment
Grid provides two levels of alignment:
| Property | Scope | Controls |
|---|---|---|
justify-items | Container | Horizontal alignment of all items |
align-items | Container | Vertical alignment of all items |
place-items | Container | Both axes (align / justify) |
justify-self | Item | Override horizontal for one item |
align-self | Item | Override vertical for one item |
.grid-container {
place-items: center;
}
.stretch-item {
align-self: stretch;
}
Try It Yourself
Experiment with grid areas, column spans, and responsive patterns in our CSS Grid Generator. Adjust tracks visually and copy production-ready CSS.
Related Guides
- CSS Grid Guide — Core grid concepts: columns, rows, gaps, and units
- CSS Layout Systems — Grid vs Flexbox comparison and combined strategies