Rows and columns, together
Flexbox arranges items along one line. CSS Grid arranges them in rows and columns at the same time, like a spreadsheet or newspaper layout. Where Flexbox lets content decide the layout, Grid lets you design the layout first and place content into it. It is the right tool for page layouts, galleries and anything where items in different rows should line up.
Your first grid
Put display: grid on the parent and describe the columns:
<style>
.grid {
display: grid;
grid-template-columns: 1fr 1fr 1fr; /* three equal columns */
gap: 12px;
}
.grid div { background: #818cf8; color: white; padding: 20px; border-radius: 8px; text-align: center; }
</style>
<div class="grid">
<div>1</div><div>2</div><div>3</div>
<div>4</div><div>5</div><div>6</div>
</div>You defined the columns only; the browser creates rows automatically as items fill them left to right, top to bottom. gap is the space between rows and columns (also written row-gap and column-gap).
The fr unit
fr stands for "fraction of the free space". Grid subtracts fixed sizes and gaps first, then shares the rest:
grid-template-columns: 1fr 1fr 1fr; /* three equal */
grid-template-columns: 1fr 2fr; /* second is twice as wide */
grid-template-columns: 240px 1fr; /* fixed sidebar, flexible main */
grid-template-columns: 200px 1fr 200px;fr is why a sidebar layout is one line.
<style>
.page { display: grid; grid-template-columns: 160px 1fr; gap: 12px; }
.side { background: #fecaca; padding: 12px; }
.main { background: #bbf7d0; padding: 12px; }
</style>
<div class="page">
<aside class="side">Sidebar 160px</aside>
<main class="main">Main content takes everything that is left.</main>
</div>repeat() and minmax()
Typing 1fr five times is tedious. repeat(count, size) does it for you:
grid-template-columns: repeat(4, 1fr); /* four equal columns */minmax(min, max) sets a track's allowed size range: at least min, at most max.
The responsive grid, no media query
Combine repeat, auto-fit and minmax for the most useful Grid recipe there is:
<style>
.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
gap: 12px;
}
.cards div { background: #fde68a; padding: 24px; border-radius: 8px; text-align: center; }
</style>
<div class="cards">
<div>A</div><div>B</div><div>C</div><div>D</div><div>E</div><div>F</div>
</div>Read it as: "make as many columns as will fit, each at least 140px, and let them share the leftover space equally." Resize the preview: columns appear and disappear on their own. The result is a layout that adapts from phone to desktop with a single line and no breakpoints.
auto-fit collapses empty tracks so the items stretch; auto-fill keeps the empty tracks, leaving gaps. Start with auto-fit.
Spanning tracks
Items can take more than one cell:
<style>
.grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; }
.grid div { background: #a5b4fc; padding: 16px; border-radius: 6px; }
.wide { grid-column: span 2; background: #f9a8d4 !important; }
.tall { grid-row: span 2; background: #86efac !important; }
</style>
<div class="grid">
<div class="wide">spans 2 columns</div><div>2</div><div>3</div>
<div class="tall">spans 2 rows</div><div>5</div><div>6</div><div>7</div>
<div>8</div><div>9</div><div>10</div>
</div>You can also place an item by line numbers: grid-column: 1 / 3 means "from line 1 to line 3" (two columns). Lines are numbered starting at 1, and -1 is the last line.
Rows
Rows are created for you at the height of their content. To set them, use grid-template-rows, or grid-auto-rows for all the automatic ones:
.grid { grid-auto-rows: minmax(100px, auto); } /* at least 100px, taller if needed */Grid versus Flexbox
| Use Grid when | Use Flexbox when |
|---|---|
| You need rows and columns together | You have one row or one column |
| The layout comes first, content fits in | The content decides the sizes |
| Items in different rows must line up | Items just need spacing and alignment |
They work well together: Grid for the page, Flexbox inside the components.
Common mistakes
- Putting
display: gridon the items, not the parent. - Using fixed pixel columns that overflow on phones. Use
fr,minmaxandauto-fit. - Using margins between items instead of
gap. - Forgetting
box-sizingfor padded items. - Placing every item by number when automatic placement is simpler.
Exercise
Build a gallery of eight tiles that has 3 columns of equal width on any screen at least 600px wide, but is flexible below that, using only one grid declaration and gap.
Show one possible answer
<style>
.gallery { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 12px; }
.gallery div { aspect-ratio: 1; background: #c7d2fe; border-radius: 8px; }
</style>
<div class="gallery">
<div></div><div></div><div></div><div></div>
<div></div><div></div><div></div><div></div>
</div>At 600px or wider the 180px minimum fits three columns; narrower, it falls to two or one automatically.
Key points
- display grid on a parent turns its direct children into grid items placed in rows and columns.
- grid-template-columns defines the columns, and the fr unit shares leftover space in proportions.
- repeat with auto-fit and minmax builds a responsive grid that needs no media queries.
- gap sets the space between rows and columns, and items can span several tracks with grid-column.
- Use Grid for layouts in two dimensions and Flexbox for a single row or column.