CSS Grid
Table of Contents
CSS Grid is a two-dimensional layout system — it handles both rows and columns simultaneously. While Flexbox excels at laying out items in a single direction, Grid shines when you need to control placement in both dimensions at once: page layouts, card grids, dashboards, and anything with a structured arrangement.
The Basics
Like Flexbox, Grid works on a parent-child relationship. Set display: grid on the container, then define your columns and rows:
<div class="grid-container">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
<div class="item">5</div>
<div class="item">6</div>
</div>
.grid-container {
display: grid;
grid-template-columns: 200px 200px 200px;
gap: 16px;
}
This creates a 3-column grid where each column is 200px wide, with 16px gaps between items. Items flow into the grid automatically, filling row by row.
Defining Columns and Rows
Fixed sizes
.grid {
display: grid;
grid-template-columns: 200px 300px 200px;
grid-template-rows: 100px 200px;
}
The fr unit (fractional)
fr distributes available space proportionally — it’s the most useful unit in Grid:
.grid {
display: grid;
grid-template-columns: 1fr 2fr 1fr; /* middle column is twice as wide */
}
Mixing units
.layout {
display: grid;
grid-template-columns: 250px 1fr; /* fixed sidebar, fluid content */
}
repeat()
Avoid repetition:
/* Instead of: 1fr 1fr 1fr 1fr */
.grid {
grid-template-columns: repeat(4, 1fr);
}
/* Repeating patterns */
.grid {
grid-template-columns: repeat(3, 1fr 2fr); /* 1fr 2fr 1fr 2fr 1fr 2fr */
}
Gap (Spacing)
.grid {
gap: 16px; /* equal row and column gaps */
gap: 20px 16px; /* row-gap column-gap */
row-gap: 20px; /* only between rows */
column-gap: 16px; /* only between columns */
}
Placing Items
By default, items flow into the grid in order. But you can place them explicitly using grid lines (numbered starting at 1):
.header {
grid-column: 1 / 4; /* span from line 1 to line 4 (all 3 columns) */
}
.sidebar {
grid-column: 1 / 2; /* first column */
grid-row: 2 / 4; /* span rows 2 and 3 */
}
.content {
grid-column: 2 / 4; /* columns 2 and 3 */
}
Shorthand with span
.wide-item {
grid-column: span 2; /* take up 2 columns from current position */
}
.tall-item {
grid-row: span 3; /* take up 3 rows */
}
A Complete Page Layout
<div class="page">
<header class="header">Header</header>
<nav class="sidebar">Sidebar</nav>
<main class="content">Content</main>
<footer class="footer">Footer</footer>
</div>
.page {
display: grid;
grid-template-columns: 250px 1fr;
grid-template-rows: 60px 1fr 50px;
min-height: 100vh;
gap: 0;
}
.header {
grid-column: 1 / -1; /* -1 means "last line" — spans full width */
}
.sidebar {
grid-column: 1;
grid-row: 2;
}
.content {
grid-column: 2;
grid-row: 2;
}
.footer {
grid-column: 1 / -1;
}
Named Grid Areas
For complex layouts, named areas are more readable than line numbers:
.page {
display: grid;
grid-template-columns: 250px 1fr;
grid-template-rows: 60px 1fr 50px;
grid-template-areas:
"header header"
"sidebar content"
"footer footer";
min-height: 100vh;
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.content { grid-area: content; }
.footer { grid-area: footer; }
The visual layout of the grid-template-areas value mirrors the actual page layout — making it easy to understand at a glance.
Alignment
Aligning items within their cells
.grid {
/* Align all items */
justify-items: center; /* horizontal: start | end | center | stretch */
align-items: center; /* vertical: start | end | center | stretch */
}
/* Align a single item */
.special-item {
justify-self: end;
align-self: start;
}
Aligning the entire grid within its container
.grid {
justify-content: center; /* horizontal alignment of the grid itself */
align-content: center; /* vertical alignment of the grid itself */
}
Responsive Grids
auto-fill and auto-fit with minmax()
This is Grid’s killer feature for responsive design — no media queries needed:
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 24px;
}
This creates as many columns as will fit, each at least 300px wide, expanding to fill available space. As the viewport shrinks, columns drop to the next row automatically.
auto-fill vs auto-fit:
auto-fill— creates empty tracks if there’s extra spaceauto-fit— collapses empty tracks, letting items stretch
For most card grids, auto-fill is what you want.
With media queries
For more control over breakpoints:
.grid {
display: grid;
grid-template-columns: 1fr;
gap: 16px;
}
@media (min-width: 768px) {
.grid {
grid-template-columns: repeat(2, 1fr);
}
}
@media (min-width: 1024px) {
.grid {
grid-template-columns: repeat(3, 1fr);
}
}
Implicit vs Explicit Grid
The explicit grid is what you define with grid-template-columns and grid-template-rows. If there are more items than cells, Grid creates implicit rows automatically:
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
/* Only columns defined — rows are created implicitly */
grid-auto-rows: 200px; /* control the size of implicit rows */
}
minmax() works here too:
.grid {
grid-auto-rows: minmax(100px, auto); /* at least 100px, grow to fit content */
}
Grid vs Flexbox
They’re complementary, not competing:
| Use Case | Best Tool |
|---|---|
| Navigation bar | Flexbox |
| Card grid | Grid |
| Centering one item | Flexbox |
| Full page layout | Grid |
| Items in a row with wrapping | Flexbox |
| Precise 2D placement | Grid |
| Unknown number of items in one direction | Flexbox |
In practice, you’ll use both in the same page — Grid for the overall layout, Flexbox for components within it.
Common Patterns
Equal-height cards
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 24px;
}
.card {
display: flex;
flex-direction: column;
}
.card-body {
flex: 1; /* pushes footer to bottom */
}
Holy grail layout
.layout {
display: grid;
grid-template:
"header header header" 60px
"left main right" 1fr
"footer footer footer" 50px
/ 200px 1fr 200px;
min-height: 100vh;
}
Overlapping items
Grid items can occupy the same cells — useful for image overlays:
.hero {
display: grid;
grid-template: 1fr / 1fr; /* single cell */
}
.hero img,
.hero .overlay {
grid-area: 1 / 1; /* both in the same cell */
}
.hero .overlay {
display: flex;
align-items: center;
justify-content: center;
background: rgba(0, 0, 0, 0.5);
color: white;
}
What’s Next
With Flexbox and Grid in your toolkit, you can build virtually any layout. From here, explore CSS Responsive Design to learn media queries and mobile-first approaches, or jump into JavaScript DOM Manipulation to make your layouts interactive.