CSS Grid: Complete Guide to Modern Layouts
Grid is the most powerful CSS layout system. Once you learn it, you'll never go back.
Why Grid?
Before Grid:
- Floats (hacky, fragile)
- Flexbox (1D only — rows OR columns)
- Tables (not semantic)
- Absolute positioning (breaks easily)
- Bootstrap grid (lots of markup)
After Grid:
- 2D layout (rows AND columns simultaneously)
- Clean semantic HTML
- No extra wrapper divs
- Responsive without media queries (sometimes)
- Align things that were impossible before
The Basics
<div class="grid-container">
<div class="header">Header</div>
<div class="sidebar">Sidebar</div>
<div class="main">Main Content</div>
<div class="footer">Footer</div>
</div>
.grid-container {
display: grid;
/* Define columns: 3 columns */
grid-template-columns: 200px 1fr 200px;
/* Column 1: 200px fixed | Column 2: fills remaining space | Column 3: 200px fixed */
/* Define rows: 4 rows */
grid-template-rows: auto 1fr auto 80px;
/* Row 1: content height | Row 2: fills space | Row 3: content height | Row 4: 80px fixed */
gap: 20px; /* Gap between all items (row + column) */
row-gap: 10px; /* Row gap only */
column-gap: 15px; /* Column gap only */
}
The fr Unit (Fraction)
/* fr = "fraction of available space" */
grid-template-columns: 1fr 1fr 1fr;
/* Three equal columns */
grid-template-columns: 2fr 1fr;
/* First column is twice as wide as second */
grid-template-columns: 200px 1fr 200px;
/* Fixed - Flexible - Fixed */
grid-template-columns: repeat(3, 1fr);
/* Same as 1fr 1fr 1fr but cleaner */
grid-template-columns: minmax(200px, 1fr) minmax(200px, 1fr);
/* Each column: minimum 200px, then share remaining equally */
grid-template-columns: fit-content(300px) fit-content(300px);
/* Columns size to their content, max 300px */
Placing Items
.item {
/* Place in specific column/row */
grid-column: 2; /* Start at column 2 */
grid-column: 1 / 3; /* Span from col 1 to col 3 (covers 2 cols) */
grid-row: 1 / span 2; /* Row 1, spans 2 rows */
/* Shorthand */
grid-area: 1 / 2 / 3 / 4; /* row-start / col-start / row-end / col-end */
}
/* Named areas (my favorite feature!) */
.layout {
display: grid;
grid-template-columns: 200px 1fr;
grid-template-rows: auto 1fr auto;
gap: 16px;
grid-template-areas:
"header header"
"sidebar main"
"footer footer";
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.footer { grid-area: footer; }
/* Visual layout matches the ASCII art! Change layout by rearranging template-areas */
Alignment & Justification
.grid {
display: grid;
grid-template-columns: repeat(3, 100px);
grid-template-rows: repeat(3, 100px);
height: 400px;
/* Align items WITHIN their cells */
align-items: start; /* Top of cell */
align-items: center; /* Center vertically */
align-items: end; /* Bottom of cell */
align-items: stretch; /* Fill entire cell (default) */
/* Justify items WITHIN their cells */
justify-items: start; /* Left of cell */
justify-items: center; /* Center horizontally */
justify-items: end; /* Right of cell */
justify-items: stretch; /* Fill entire cell (default) */
/* Place items: shorthand for align-items + justify-items */
place-items: center center; /* Both vertical + horizontal center */
/* Align ENTIRE grid within container */
align-content: start; /* Pack rows to top */
align-content: center; /* Center rows vertically */
align-content: end; /* Pack rows to bottom */
align-content: space-between; /* Space between rows */
align-content: space-around; /* Space around each row */
align-content: space-evenly; /* Equal spacing everywhere */
/* Justify ENTIRE grid within container */
justify-content: start;
justify-content: center;
justify-content: end;
justify-content: space-between;
/* Place entire grid: shorthand */
place-content: center center;
}
/* Per-item alignment (overrides container defaults) */
.specific-item {
align-self: center;
justify-self: end;
place-self: center start;
}
Auto-Fit & Auto-Fill (Responsive Without Media Queries!)
/* auto-fill: Create as many columns as will fit */
.grid-auto-fill {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 16px;
/* Result: As many 250px+ columns as fit in the container.
When window shrinks, columns drop to next line automatically! */
}
/* auto-fit: Like fill but empty tracks collapse */
.grid-auto-fit {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 16px;
/* Similar but existing items expand to fill space when there are
fewer items than columns */
}
/* Practical card layout */
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 24px;
}
/* On 1400px screen → 5 cards per row
On 1000px screen → 3 cards per row
On 600px screen → 1 card per row
All with ONE line of CSS! */
Implicit Grid
.grid {
display: grid;
grid-template-columns: 1fr 1fr; /* Only 2 explicit columns */
grid-auto-rows: 150px; /* Height for implicitly created rows */
grid-auto-flow: row; /* Place new items in new rows (default) */
/* or */
grid-auto-flow: column; /* Place new items in new columns */
grid-auto-columns: 100px; /* Width for implicit columns */
}
/* When you have more items than defined cells,
Grid creates implicit rows/columns automatically.
These properties control those implicit cells. */
Subgrid (The New Game Changer!)
/* Child grid can inherit parent's track definitions! */
.parent {
display: grid;
grid-template-columns: 200px 1fr 200px;
gap: 16px;
}
.child-with-subgrid {
display: grid;
grid-template-columns: subgrid; /* Inherits parent's columns! */
grid-template-rows: subgrid; /* Inherits parent's rows! */
grid-column: span 3; /* Span all 3 parent columns */
gap: inherit;
}
/* Before Subgrid: Nested grids didn't align with parent grid lines.
After Subgrid: Perfect alignment between nested and parent grids.
Essential for complex layouts like card components inside a grid. */
Common Layout Patterns
Holy Grail Layout
.holy-grail {
display: grid;
grid-template:
"header header header" auto
"sidebar main aside" 1fr
"footer footer footer" 80px
/ 200px 1fr 200px;
gap: 16px;
min-height: 100vh;
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.aside { grid-area: aside; }
.footer { grid-area: footer; }
@media (max-width: 768px) {
.holy-grail {
grid-template:
"header"
"main"
"sidebar"
"aside"
"footer"
/ 1fr;
}
}
Dashboard Grid
.dashboard {
display: grid;
grid-template-columns: repeat(12, 1fr); /* 12-column system */
grid-template-rows: auto 1fr auto;
gap: 16px;
padding: 16px;
min-height: 100vh;
}
.dash-header { grid-area: 1 / 1 / 2 / 13; } /* Full width */
.dash-sidebar { grid-area: 2 / 1 / 3 / 3; } /* Col 1-2, rows 2-3 */
.dash-main { grid-area: 2 / 3 / 3 / 11; } /* Col 3-10, rows 2-3 */
.dash-right { grid-area: 2 / 11 / 3 / 13; } /* Col 11-12, rows 2-3 */
.dash-footer { grid-area: 3 / 1 / 4 / 13; } /* Full width */
Gallery/Masonry-like
.gallery {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 12px;
}
.gallery-item:nth-child(3n+1) { grid-row: span 2; } /* Every 3rd item is taller */
.gallery-item:nth-child(5n) { grid-column: span 2; } /* Every 5th item is wider */
Quick Reference Card
| Property | What It Does |
|---|---|
display: grid |
Enable grid layout |
grid-template-columns |
Define column sizes |
grid-template-rows |
Define row sizes |
gap |
Space between items |
grid-area |
Name/place an item |
grid-template-areas |
Visual layout with names |
align-items |
Vertical align in cells |
justify-items |
Horizontal align in cells |
place-items |
Shorthand align + justify |
auto-fill/auto-fit |
Responsive columns |
minmax(min, max) |
Flexible sizing range |
subgrid |
Inherit parent tracks |
Are you using Grid yet? What's your favorite pattern?
Follow @armorbreak for more frontend content.
Top comments (0)