What is CSS Grid?
CSS Grid is a layout system designed for two-dimensional layouts: rows and columns at the same time. If Flexbox is great for “a row of things” (or “a column of things”), Grid is great for “a whole layout”.
You’ll typically reach for Grid when:
- You want a predictable layout with both rows and columns.
- You want to place items in specific spots (and not rely on the DOM order alone).
- You want responsive columns that wrap nicely without dozens of media queries.
Let’s build the skill step by step, with interactive playgrounds you can click through.
Your first grid: display grid and columns
A grid starts when you set display: grid on a container.
Then you define columns (and optionally rows) with grid-template-columns and
grid-template-rows.
In this first demo, we’ll create 3 columns and let items automatically fill them row by row.
.grid {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
}
.grid {
display: grid;
grid-template-columns: 200px 1fr 120px;
}
.grid {
display: grid;
grid-template-columns: 2fr 1fr 1fr;
}
*,
::before,
::after {
box-sizing: border-box;
}
.grid {
padding: 16px;
border: 3px solid #111;
background: #f6f6f6;
}
.item {
font-family: ui-monospace, SFMono-Regular, Menlo;
font-size: 14px;
padding: 14px;
border: 2px solid #111;
background: #fff;
}
Item 1Item 2Item 3Item 4Item 5Item 6Item 7
A quick mental model:
- The container defines the grid tracks (columns and rows).
- The children become grid items and get auto-placed into available cells.
- When you run out of columns, Grid moves to the next row.
Fractions and repeat
The fr unit means “a fraction of the available space”.
It’s one of the reasons Grid feels so natural for layouts.
And when you’re repeating a pattern, use repeat() so your CSS stays readable.
.grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
}
.grid {
display: grid;
grid-template-columns: repeat(6, 1fr);
}
.grid {
display: grid;
grid-template-columns: 2fr repeat(2, 1fr);
}
*,
::before,
::after {
box-sizing: border-box;
}
.grid {
padding: 16px;
border: 3px solid #111;
background: #f6f6f6;
}
.item {
font-family: ui-monospace, SFMono-Regular, Menlo;
font-size: 14px;
padding: 14px;
border: 2px solid #111;
background: #fff;
}
ABCDEFGH
Tip: repeat(12, 1fr) is a simple way to build a “12-column grid” system.
You don’t need it, but it can be handy for page layouts.
Rows: explicit rows and auto rows
Columns get the spotlight, but rows matter too.
You can define explicit rows with grid-template-rows.
For rows created automatically (implicit rows), you control their size with grid-auto-rows.
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: 80px 80px;
}
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-auto-rows: 70px;
}
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-auto-rows: minmax(60px, auto);
}
*,
::before,
::after {
box-sizing: border-box;
}
.grid {
padding: 16px;
border: 3px solid #111;
background: #f6f6f6;
}
.item {
font-family: ui-monospace, SFMono-Regular, Menlo;
font-size: 14px;
padding: 14px;
border: 2px solid #111;
background: #fff;
}
.item.big {
padding: 24px 14px;
}
123 (taller content)4567
minmax() is a superstar:
- The first value is the minimum size.
- The second value is the maximum size.
-
Using
autoas the max lets content grow when needed.
Gap: spacing without margin gymnastics
Use gap to add space between grid cells.
This avoids the “margin on children” headache and keeps spacing consistent.
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 0px;
}
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 12px;
}
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
row-gap: 18px;
column-gap: 6px;
}
*,
::before,
::after {
box-sizing: border-box;
}
.grid {
padding: 16px;
border: 3px solid #111;
background: #f6f6f6;
}
.item {
font-family: ui-monospace, SFMono-Regular, Menlo;
font-size: 14px;
padding: 14px;
border: 2px solid #111;
background: #fff;
}
AlphaBetaGammaDeltaEpsilonZeta
If your layout suddenly feels “too cramped” or “too airy”, gap is often the first dial to turn.
Implicit grid and auto-placement
When you don’t explicitly place items, Grid auto-places them. Most of the time that’s exactly what you want.
The property that controls the auto-placement algorithm is grid-auto-flow.
The default is row (fill a row, then move down).
.grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-auto-flow: row;
}
.grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-auto-flow: column;
}
.grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-auto-flow: row dense;
}
*,
::before,
::after {
box-sizing: border-box;
}
.grid {
padding: 16px;
border: 3px solid #111;
background: #f6f6f6;
gap: 12px;
}
.item {
font-family: ui-monospace, SFMono-Regular, Menlo;
font-size: 14px;
padding: 14px;
border: 2px solid #111;
background: #fff;
}
.item.wide {
grid-column: span 2;
}
12 (span 2)34567 (span 2)89
About dense:
- It lets Grid “backfill” gaps when items span multiple cells.
- It can change the visual order compared to the DOM order.
- That can be fine for purely decorative grids, but be careful with content that needs a logical reading order.
Interactive controls: tweak columns and gap with sliders
Let’s make the grid feel more “alive”. In this playground, sliders control the three column fractions and the gap value.
Notice how changing fractions changes the layout without needing fixed widths. This is one of Grid’s sweet spots.
.grid {
display: grid;
grid-template-columns: 2fr 1fr 1fr;
gap: 12px;
}
*,
::before,
::after {
box-sizing: border-box;
}
.grid {
padding: 16px;
border: 3px solid #111;
background: #f6f6f6;
}
.item {
font-family: ui-monospace, SFMono-Regular, Menlo;
font-size: 14px;
padding: 14px;
border: 2px solid #111;
background: #fff;
}
.item strong {
font-weight: 700;
}
Card AWants more spaceCard BHappy to be smallerCard CAlso smallerCard DWraps to the next rowCard EGrid is doing the math
Responsive grids: minmax and auto-fit auto-fill
One of the most useful Grid patterns is “cards that wrap nicely”. Instead of picking a column count per breakpoint, you can say:
- Each card should be at least this wide.
- Then fit as many columns as possible.
That’s exactly what repeat(auto-fill, minmax(...)) does.
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
}
*,
::before,
::after {
box-sizing: border-box;
}
.grid {
padding: 16px;
border: 3px solid #111;
background: #f6f6f6;
gap: 12px;
}
.item {
font-family: ui-monospace, SFMono-Regular, Menlo;
font-size: 14px;
padding: 14px;
border: 2px solid #111;
background: #fff;
}
Card 1Card 2Card 3Card 4Card 5Card 6Card 7
auto-fit vs auto-fill (the friendly version):
-
auto-fitcollapses “empty tracks” so items stretch and fill the row. -
auto-fillkeeps the tracks reserved, even if there aren’t enough items to fill them.
In many “card grid” cases, auto-fill is the better choice, since it keeps the layout more consistent as
items are added or removed.
Alignment in Grid
Grid alignment comes in two flavors:
- Item alignment inside each cell (how content aligns within its grid area)
- Track alignment inside the container (how the whole grid aligns if there’s extra space)
The most common beginner-friendly trio is:
justify-items, align-items, and place-items.
justify-items with a radio group
justify-items controls horizontal alignment of items within their grid cells.
Use the radio buttons to switch values and see what changes.
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
justify-items: stretch;
}
*,
::before,
::after {
box-sizing: border-box;
}
.grid {
padding: 16px;
border: 3px solid #111;
background: #f6f6f6;
gap: 12px;
}
.item {
font-family: ui-monospace, SFMono-Regular, Menlo;
font-size: 14px;
padding: 14px;
border: 2px solid #111;
background: #fff;
width: 80px;
}
OneTwoThreeFourFiveSix
Notes:
-
stretchis the default for many sizing situations, so items expand to fill the cell. - If your items have an explicit width (like in this demo), the difference between values becomes very obvious.
place-items and content alignment
place-items is shorthand for align-items and justify-items.
It’s great when you want consistent alignment in both directions.
Meanwhile, justify-content and align-content align the whole grid tracks inside the
container
when there’s extra space (usually when the grid is smaller than its container).
.grid {
display: grid;
grid-template-columns: repeat(3, 120px);
place-items: start;
justify-content: start;
}
.grid {
display: grid;
grid-template-columns: repeat(3, 120px);
place-items: center;
justify-content: center;
}
.grid {
display: grid;
grid-template-columns: repeat(3, 120px);
place-items: end;
justify-content: space-between;
}
*,
::before,
::after {
box-sizing: border-box;
}
.grid {
width: 100%;
min-height: 240px;
padding: 16px;
border: 3px solid #111;
background: #f6f6f6;
gap: 12px;
}
.item {
font-family: ui-monospace, SFMono-Regular, Menlo;
font-size: 14px;
padding: 14px;
border: 2px solid #111;
background: #fff;
}
Box 1Box 2Box 3Box 4Box 5Box 6
Placing items: grid-column and grid-row
Auto-placement is great, but sometimes you want an item to span columns or land in a specific spot.
That’s where grid-column and grid-row come in.
The most beginner-friendly pattern is span:
grid-column: span 2 means “take up two columns”.
.feature {
grid-column: span 2;
}
.feature {
grid-column: 1 / -1;
}
.feature {
grid-column: 2 / 4;
grid-row: 1 / 3;
}
*,
::before,
::after {
box-sizing: border-box;
}
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-auto-rows: 80px;
padding: 16px;
border: 3px solid #111;
background: #f6f6f6;
gap: 12px;
}
.item {
font-family: ui-monospace, SFMono-Regular, Menlo;
font-size: 14px;
padding: 14px;
border: 2px solid #111;
background: #fff;
display: grid;
place-items: center;
}
.feature {
background: #fff;
border-style: dashed;
}
Feature23456
A couple of helpful details:
- Line numbers start at 1.
-
Negative line numbers count from the end, so
-1is the last line. -
grid-column: 1 / -1is a popular trick for “span the full width”.
Named layouts with grid-template-areas
grid-template-areas lets you name regions of the grid and place items into them.
It’s often described as “ASCII art layout”, and honestly, that’s not wrong.
This can be quite readable for page layouts like header / sidebar / main / footer.
.grid {
display: grid;
grid-template-columns: 220px 1fr;
grid-template-areas:
"nav main";
}
.nav {
grid-area: nav;
}
.main {
grid-area: main;
}
.grid {
display: grid;
grid-template-columns: 1fr;
grid-template-areas:
"nav"
"main";
}
.nav {
grid-area: nav;
}
.main {
grid-area: main;
}
.grid {
display: grid;
grid-template-columns: 100px 1fr 100px;
grid-template-areas:
"nav main aside";
}
.nav {
grid-area: nav;
}
.main {
grid-area: main;
}
.aside {
grid-area: aside;
}
*,
::before,
::after {
box-sizing: border-box;
}
.grid {
padding: 16px;
border: 3px solid #111;
background: #f6f6f6;
gap: 12px;
min-height: 240px;
}
.panel {
font-family: ui-monospace, SFMono-Regular, Menlo;
font-size: 14px;
padding: 14px;
border: 2px solid #111;
background: #fff;
}
.panel p {
margin: 0;
}
Nav
Links go here
Main
Your content area
Aside
Extras and widgets
A few rules for areas:
-
Each row in
grid-template-areasmust have the same number of columns (same number of “cells”). -
Use a dot
.for an empty cell. - Names must form rectangles (no weird L-shaped areas).
A practical layout pattern: header, content, and footer
Here’s a simple layout you can reuse constantly:
- A header that spans full width
- A content area with a sidebar on large screens
- A footer that spans full width
We’ll use areas for clarity, plus a media query to switch to a single column on smaller screens.
.page {
display: grid;
grid-template-columns: 240px 1fr;
grid-template-areas:
"header header"
"sidebar main"
"footer footer";
}
@media (max-width: 700px) {
.page {
grid-template-columns: 1fr;
grid-template-areas:
"header"
"main"
"sidebar"
"footer";
}
}
.page {
display: grid;
grid-template-columns: minmax(180px, 260px) 1fr;
grid-template-areas:
"header header"
"sidebar main"
"footer footer";
}
*,
::before,
::after {
box-sizing: border-box;
}
.page {
padding: 16px;
border: 3px solid #111;
background: #f6f6f6;
gap: 12px;
min-height: 320px;
}
.panel {
font-family: ui-monospace, SFMono-Regular, Menlo;
font-size: 14px;
padding: 14px;
border: 2px solid #111;
background: #fff;
}
.header {
grid-area: header;
}
.sidebar {
grid-area: sidebar;
}
.main {
grid-area: main;
}
.footer {
grid-area: footer;
}
.panel p {
margin: 0;
}
Header
Logo, nav, search
Main
Articles, products, content
If you only memorize one Grid layout approach for real projects, this one is a solid choice. It’s readable, flexible, and scales well.
Common Grid pitfalls (and how to fix them)
-
“My grid items aren’t aligning.”
Check whether you meant
justify-items/align-items(items inside cells), orjustify-content/align-content(grid tracks inside the container). -
“Why are my columns overflowing?”
Try
minmax(0, 1fr)for columns that contain long content, especially if you see overflow from long words or code. -
“I used dense and my order looks weird.”
That’s expected.
densecan backfill gaps and change visual order. Avoid it for content where reading order matters. -
“I’m mixing margins, gaps, and padding and everything feels inconsistent.”
Use
gapfor spacing between grid items, and padding on the container for spacing around the grid.
Quick Grid cheat sheet
-
Turn it on:
display: grid -
Columns:
grid-template-columns -
Rows:
grid-template-rowsandgrid-auto-rows -
Spacing:
gap,row-gap,column-gap -
Responsive cards:
repeat(auto-fill, minmax(180px, 1fr)) -
Align items in cells:
justify-items,align-items,place-items -
Align the grid in container:
justify-content,align-content -
Place items:
grid-column,grid-row,span -
Named layouts:
grid-template-areasandgrid-area
CSS Grid Conclusion
CSS Grid is a powerful tool for building complex, responsive layouts with less code and more flexibility than ever before. By mastering the core concepts and properties, you can create designs that adapt gracefully to different screen sizes and content needs.
Learn more about its closely related layout option, inline-grid, in the CSS Display Inline-Grid
Interactive Tutorial.
If you don't already know about flex, check out the CSS Flexbox Interactive Tutorial.
