CSS Grid: A Practical Beginner's Guide
CSS Grid is the modern tool for two-dimensional layout. This guide covers tracks, the fr unit, gaps, spans, and responsive grids — everything you need to build real page layouts.
What you'll learn
- ✓What CSS Grid is and how it differs from Flexbox
- ✓How to define columns and rows with grid-template-columns and grid-template-rows
- ✓The fr unit and why it is unique to Grid
- ✓How gap controls spacing without margin tricks
- ✓Placing and spanning items with grid-column and grid-row
- ✓Building responsive grids with repeat(), auto-fit, and minmax()
Prerequisites
- •Comfort with Flexbox helps — see CSS Flexbox
Flexbox is the right tool when you are arranging items along a single line — a row or a column. For everything else — rows and columns at the same time, full-page layouts, dashboards, galleries — the right tool is CSS Grid.
Grid is two-dimensional. You define a set of tracks (columns and rows), and items snap into the cells those tracks create. Once it clicks, layouts that used to take an afternoon become a few lines of CSS.
Flexbox vs. Grid
The shortest possible distinction:
- Flexbox arranges items along one axis. Use it for navigation bars, button rows, vertical stacks.
- Grid arranges items along two axes. Use it for page layouts, image galleries, card grids, forms with aligned labels.
Real pages use both. It is completely normal for a page to use Grid for the outer template and Flexbox inside each region. They cooperate well.
Turning on Grid
You turn an element into a grid container by setting display: grid. Then you describe the columns and rows.
<div class="grid">
<div>A</div>
<div>B</div>
<div>C</div>
<div>D</div>
<div>E</div>
<div>F</div>
</div>
.grid {
display: grid;
grid-template-columns: 200px 200px 200px; /* three 200px columns */
}
The six children flow into the three columns, wrapping to new rows as needed. You have not had to write anything about rows — Grid creates them automatically as items overflow.
The fr unit
Pixels work, but real layouts need to flex with the viewport. Grid introduces a unit specifically for this: fr, short for “fractional unit.” It means “one share of the remaining space.”
.grid {
display: grid;
grid-template-columns: 1fr 1fr 1fr; /* three equal columns */
}
Three 1fr columns means each column takes one-third of the container width. Change the proportions by changing the numbers:
.grid {
grid-template-columns: 1fr 2fr 1fr; /* middle column is twice as wide */
}
You can mix fixed and flexible tracks freely:
.grid {
grid-template-columns: 200px 1fr 200px; /* fixed sidebars, fluid middle */
}
That single line is the classic “sidebar, content, sidebar” page layout. Try doing it with floats and you will appreciate Grid forever.
Defining rows
grid-template-rows works the same way:
.grid {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: 100px 200px; /* first row 100px, second 200px */
}
If you do not define rows, Grid creates them on demand and sizes them to fit their content. That is what you want most of the time.
The gap property
Spacing between grid cells used to require margin gymnastics. With Grid (and modern Flexbox), gap handles it directly:
.grid {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 1rem; /* 1rem between every row and column */
}
You can split it into row and column gaps:
.grid {
row-gap: 2rem;
column-gap: 1rem;
}
gap is one of the small joys of modern CSS. Use it.
Try it yourself. Make a grid with three columns of 1fr each, a gap of 1rem, and six child divs with colored backgrounds. Resize the browser. Watch the columns flex while the gaps stay constant. Then change one column to 2fr and see what happens.
repeat() for cleaner templates
Writing 1fr 1fr 1fr 1fr 1fr 1fr gets old fast. repeat() is the shorthand:
.grid {
grid-template-columns: repeat(6, 1fr); /* six equal columns */
}
You can mix repeat() with other tracks:
.grid {
grid-template-columns: 200px repeat(3, 1fr) 200px;
}
Placing items with grid-column and grid-row
By default, items flow into the next available cell. You can override that and place an item anywhere — including spanning multiple columns or rows.
.feature {
grid-column: 1 / 3; /* span from column line 1 to column line 3 (two columns) */
grid-row: 1 / 3; /* span from row line 1 to row line 3 (two rows) */
}
Grid lines are numbered starting from 1. A three-column grid has four column lines: 1, 2, 3, 4. grid-column: 1 / 3 means “start at line 1 and end at line 3” — covering columns 1 and 2.
The shorthand span is often easier to read:
.feature {
grid-column: span 2; /* span 2 columns starting wherever this item lands */
grid-row: span 2;
}
A practical example — a photo gallery where one tile is twice as big:
.gallery {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 1rem;
}
.gallery > .featured {
grid-column: span 2;
grid-row: span 2;
}
The featured tile occupies a 2×2 area; the rest flow around it. Three lines of CSS, no JavaScript.
Responsive grids with auto-fit and minmax()
The most powerful pattern in all of CSS Grid is this:
.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 1rem;
}
Read it slowly. minmax(220px, 1fr) says “each track should be at least 220px and at most 1fr.” auto-fit says “fit as many tracks as you can at that size.”
The result: on a wide screen the grid shows many columns; on a narrow screen it shows one. The browser does the math. You did not write a single media query.
<div class="cards">
<article class="card">...</article>
<article class="card">...</article>
<article class="card">...</article>
<article class="card">...</article>
</div>
Resize the browser and the cards reflow automatically. This one line is the building block of nearly every modern card layout.
auto-fill is a close cousin of auto-fit. The difference: auto-fit collapses empty tracks so the items grow to fill the row; auto-fill keeps empty tracks. For most cases auto-fit is what you want.
Try it yourself. Build the .cards grid above. Drop six card divs inside. Resize the browser from very wide to very narrow. Count how many columns appear at each width. Then change 220px to 300px and watch the breakpoints shift.
A worked example: a page layout
A classic three-region layout — header across the top, sidebar on the left, content on the right, footer across the bottom:
<div class="page">
<header class="page__header">Site title</header>
<nav class="page__sidebar">Navigation</nav>
<main class="page__main">Main content</main>
<footer class="page__footer">Footer</footer>
</div>
.page {
display: grid;
grid-template-columns: 200px 1fr;
grid-template-rows: auto 1fr auto;
gap: 1rem;
min-height: 100vh;
}
.page__header {
grid-column: 1 / 3; /* span both columns */
}
.page__footer {
grid-column: 1 / 3; /* span both columns */
}
/* sidebar and main land in their default cells */
The header spans the full width of the top row. The sidebar takes the first column of the middle row. The main content takes the second column. The footer spans the full width of the bottom row. Done in ten lines.
Grid template areas (an even cleaner option)
For named layouts, grid-template-areas lets you draw the layout in CSS as if it were ASCII art:
.page {
display: grid;
grid-template-columns: 200px 1fr;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"header header"
"sidebar main"
"footer footer";
gap: 1rem;
min-height: 100vh;
}
.page__header { grid-area: header; }
.page__sidebar { grid-area: sidebar; }
.page__main { grid-area: main; }
.page__footer { grid-area: footer; }
Anyone reading this CSS can see the layout instantly. Template areas are particularly nice for layouts you might rearrange at different breakpoints.
A few practical tips
- Reach for Grid for two dimensions, Flexbox for one. That single rule prevents most layout regret.
- Default to
1frfor columns. Use pixels only when you really mean a fixed width. - Use
gapinstead of margins. Always. repeat(auto-fit, minmax(...))is the responsive grid pattern to memorize.- Inspect with developer tools. Chrome and Firefox both have a Grid overlay that draws all the tracks and lines. It is the fastest way to learn.
Recap
You now know:
display: gridturns an element into a two-dimensional grid containergrid-template-columnsandgrid-template-rowsdefine the tracks- The
frunit distributes available space as fractions gapspaces tracks without margin tricksgrid-column,grid-row, andspanplace items across multiple cellsrepeat(auto-fit, minmax(220px, 1fr))is the canonical responsive grid patterngrid-template-areaslets you describe layouts visually in CSS
Next steps
You can now structure pages and arrange the regions inside them. The next thing to master is targeting — how CSS selectors find the exact elements you want to style, and what happens when multiple rules try to apply at once.
Next: CSS Selectors and Specificity Explained
Questions or feedback? Email codeloomdevv@gmail.com.