CSS Grid Complete Guide - Master Two-Dimensional Layouts
Learn CSS Grid from the ground up. Discover how to create powerful two-dimensional layouts with Grid. Master rows, columns, areas, and responsive design patterns. Perfect for developers ready to level up their CSS skills.
CSS Grid Layout is one of the most powerful tools in modern web development. While Flexbox revolutionised one-dimensional layouts, Grid brings the same level of control and flexibility to two-dimensional layouts—letting you arrange elements in rows and columns simultaneously.

If you’ve ever struggled with complex page layouts, uneven column heights, or wrestling CSS into submission for a dashboard or magazine-style design, Grid is the solution you’ve been waiting for. It turns layout tasks from frustrating hacks into clean, intuitive code.
In this guide, you’ll learn everything you need to use CSS Grid effectively—from the basics of creating a grid to advanced techniques like auto-fit, named areas, and responsive patterns that work without a single media query.
What is CSS Grid?
CSS Grid is a two-dimensional layout system that gives you complete control over both rows and columns. Think of it as placing items on a spreadsheet: you define the rows and columns, then position items wherever you want in that grid.
What Grid excels at:
- Full-page layouts with headers, sidebars, and footers
- Card grids that automatically reflow
- Magazine-style layouts with overlapping elements
- Dashboard designs with complex multi-column arrangements
- Forms with precise alignment across rows and columns
Grid vs Flexbox: When to Use Which
Grid and Flexbox aren’t competitors—they’re complementary tools:
| Use Case | Best Tool |
|---|---|
| Full page layout | CSS Grid |
| Navigation bar | Flexbox |
| Card grid | CSS Grid or Flexbox |
| Centering a button | Flexbox |
| Dashboard layout | CSS Grid |
| Form alignment | CSS Grid |
| Component interior | Flexbox |
Rule of thumb: Use Grid for the big picture (page layout), and Flexbox for the details (component alignment).
Getting Started with CSS Grid
Everything in Grid starts with one line of CSS:
.container {
display: grid;
}
That alone doesn’t do much visible work—you need to define your rows and columns. Let’s build a simple grid step by step.
Defining Columns with grid-template-columns
The most common starting point is defining how many columns you want and their sizes:
.container {
display: grid;
grid-template-columns: 200px 1fr 1fr;
}
This creates three columns: 200px wide, then two flexible columns that share the remaining space. The 1fr unit is a grid-specific fractional unit—it divides unused space proportionally.
Try this HTML with the CSS above:
<div class="container">
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
<div>Item 4</div>
<div>Item 5</div>
<div>Item 6</div>
</div>
Items 1, 2, and 3 go in the first row. Items 4, 5, and 6 wrap to the second row. Item 1 is 200px wide; items 2 and 3 share the remaining space evenly.
Defining Rows with grid-template-rows
You can also control row heights:
.container {
display: grid;
grid-template-columns: 1fr 2fr 1fr;
grid-template-rows: 100px auto 100px;
}
This creates three rows: a 100px header row, a flexible content row, and a 100px footer row.
The repeat() Function
When you have many columns of the same size, repeat() keeps your code clean:
/* Without repeat */
grid-template-columns: 1fr 1fr 1fr 1fr;
/* With repeat - much cleaner */
grid-template-columns: repeat(4, 1fr);
/* Three columns of different sizes, repeated pattern */
grid-template-columns: repeat(2, 1fr 2fr);
/* Same as: 1fr 2fr 1fr 2fr */
Gap Control
Spacing between grid items is simple with the gap property:
.container {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px; /* Both row and column gaps */
/* or separately: */
row-gap: 16px;
column-gap: 24px;
}
This replaces the old hack of using margins and negative margins on individual items—a huge quality-of-life improvement.
Placing Items on the Grid
By default, items flow into grid cells in document order (left to right, top to bottom). But Grid’s real power comes from placing items exactly where you want them.
Line-Based Placement
Grid lines are numbered starting from 1 at the top-left:
.header {
grid-column-start: 1;
grid-column-end: 4;
grid-row-start: 1;
grid-row-end: 2;
}
The shorthand version is cleaner:
.header {
grid-column: 1 / 4; /* Start at line 1, end at line 4 */
grid-row: 1 / 2; /* First row only */
}
.sidebar {
grid-column: 1 / 2; /* First column */
grid-row: 2 / 4; /* Rows 2 and 3 */
}
.content {
grid-column: 2 / 4; /* Columns 2 and 3 */
grid-row: 2 / 3; /* Row 2 only */
}
.footer {
grid-column: 1 / 4; /* Full width */
grid-row: 3 / 4; /* Last row */
}
With this HTML:
<div class="container">
<header class="header">Header</header>
<aside class="sidebar">Sidebar</aside>
<main class="content">Content</main>
<footer class="footer">Footer</footer>
</div>
You get a classic Holy Grail layout with just CSS Grid—no floats, no hacks.
Using the span Keyword
Instead of specifying end lines, you can use span to say how many cells an item should cover:
.header {
grid-column: 1 / span 3; /* Span 3 columns starting from 1 */
}
.sidebar {
grid-row: 2 / span 2; /* Span 2 rows from row 2 */
}
Named Grid Areas
For complex layouts, named areas make your CSS incredibly readable:
.container {
display: grid;
grid-template-columns: 250px 1fr;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"header header"
"sidebar content"
"footer footer";
min-height: 100vh;
gap: 16px;
}
header { grid-area: header; }
aside { grid-area: sidebar; }
main { grid-area: content; }
footer { grid-area: footer; }
The ASCII-art style of grid-template-areas makes the layout immediately understandable. Each string is a row, and each value in the row maps to a column. Use a period (.) to leave a cell empty.
/* Magazine layout with empty cells */
grid-template-areas:
"header header header"
"sidebar . content"
"footer footer footer";
The minmax() Function
minmax() sets minimum and maximum sizes for tracks, enabling responsive layouts without media queries:
.container {
display: grid;
grid-template-columns: repeat(3, minmax(200px, 1fr));
}
Each column has a minimum width of 200px and can grow up to 1fr (one fraction of available space). This prevents columns from shrinking too small while still being flexible.
Auto-Fit and Auto-Fill
These are game-changers for responsive grids:
/* Cards that automatically wrap to new rows */
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 24px;
}
What this does:
- Each card has a minimum width of 250px
- Cards grow to fill available space (1fr)
- When the container shrinks and cards would go below 250px, they wrap to a new row
- Result: a responsive card grid with zero media queries
The difference between auto-fit and auto-fill:
auto-fill: keeps empty tracks (maintains column structure even when empty)auto-fit: collapses empty tracks (columns stretch to fill space)
/* auto-fill: keeps empty columns (great for consistent grid structure) */
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
/* auto-fit: collapses empty columns (cards expand to fill space) */
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
Placing Items Explicitly
You can place items wherever you want, even out of order:
.item-1 { grid-column: 3; grid-row: 1; } /* Top-right */
.item-2 { grid-column: 1; grid-row: 3; } /* Bottom-left */
.item-3 { grid-column: 2 / 4; grid-row: 2; }
This allows completely independent placement—the item’s position in the HTML doesn’t matter. Perfect for rearranging layouts on different screen sizes.
Grid Auto Flow
Controls how items that aren’t explicitly placed are handled:
.container {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-auto-rows: minmax(100px, auto);
grid-auto-flow: row; /* Default: fill rows first */
}
/* Fill columns first instead */
.container {
grid-auto-flow: column;
}
/* Dense packing fills gaps automatically */
.container {
grid-auto-flow: row dense;
}
The dense keyword is particularly useful—it backfills gaps with smaller items, giving you a Pinterest-style masonry-like layout.
Real-World Layout: Full Page Dashboard
Let’s build a complete dashboard layout:
.dashboard {
display: grid;
grid-template-columns: 240px 1fr 300px;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"sidebar header header"
"sidebar main aside"
"sidebar footer footer";
min-height: 100vh;
gap: 0;
}
.dashboard-header { grid-area: header; }
.dashboard-sidebar { grid-area: sidebar; }
.dashboard-main { grid-area: main; }
.dashboard-aside { grid-area: aside; }
.dashboard-footer { grid-area: footer; }
<div class="dashboard">
<header class="dashboard-header">
<h1>Dashboard</h1>
<input type="search" placeholder="Search...">
</header>
<nav class="dashboard-sidebar">
<ul>
<li>Overview</li>
<li>Analytics</li>
<li>Settings</li>
</ul>
</nav>
<main class="dashboard-main">
<div class="stats-grid">
<!-- Cards -->
</div>
</main>
<aside class="dashboard-aside">
<h3>Recent Activity</h3>
<!-- Activity feed -->
</aside>
<footer class="dashboard-footer">
<p>© 2026 Dashboard</p>
</footer>
</div>
Real-World Layout: Responsive Card Gallery
A common pattern—a gallery that adapts from 1 column to 4+ columns:
.gallery {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 16px;
padding: 16px;
}
.gallery-item {
border-radius: 8px;
overflow: hidden;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.gallery-item.featured {
grid-column: span 2;
grid-row: span 2;
}
With just auto-fit and minmax, this gallery works on any screen—from mobile (1 column) to desktop (4+ columns)—without a single breakpoint. Use the featured class to make important items span multiple cells.
Real-World Layout: Holy Grail (Responsive)
The classic Holy Grail layout, made responsive with one media query:
body {
display: grid;
grid-template-columns: 200px 1fr 200px;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"header header header"
"nav main aside"
"footer footer footer";
min-height: 100vh;
margin: 0;
gap: 0;
}
@media (max-width: 768px) {
body {
grid-template-columns: 1fr;
grid-template-areas:
"header"
"nav"
"main"
"aside"
"footer";
}
}
header { grid-area: header; background: #333; color: white; padding: 1rem; }
nav { grid-area: nav; background: #f0f0f0; padding: 1rem; }
main { grid-area: main; padding: 1rem; }
aside { grid-area: aside; background: #f0f0f0; padding: 1rem; }
footer { grid-area: footer; background: #333; color: white; padding: 1rem; }
On large screens: three columns with sidebar and aside. On mobile: everything stacks vertically. One media query, and the grid-template-areas change does all the work.
Advanced: Overlapping Items
Grid items can overlap—unlike Flexbox items. This enables creative designs:
.hero {
display: grid;
grid-template-columns: 1fr 1fr;
}
.hero-image {
grid-column: 1 / 3;
grid-row: 1;
width: 100%;
height: 400px;
object-fit: cover;
}
.hero-text {
grid-column: 2 / 3;
grid-row: 1;
align-self: center;
justify-self: center;
background: rgba(0, 0, 0, 0.6);
color: white;
padding: 2rem;
z-index: 1;
}
The text box overlaps the image, positioned on the right side. The z-index controls which element sits on top.
Combining Grid with Flexbox
The best layouts use both Grid and Flexbox together:
.page {
display: grid;
grid-template-columns: 1fr 3fr;
grid-template-areas: "nav content";
min-height: 100vh;
}
nav {
grid-area: nav;
display: flex;
flex-direction: column;
gap: 12px;
padding: 1rem;
}
.content {
grid-area: content;
display: flex;
flex-wrap: wrap;
gap: 20px;
}
.card {
flex: 1 1 280px;
border-radius: 8px;
padding: 1.5rem;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
Grid controls the big picture (sidebar + content area). Flexbox handles the internal arrangement of nav links and cards.
Responsive Strategy Without Media Queries
CSS Grid can handle many responsive patterns without any breakpoints at all:
/* Auto-sizing cards */
.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(clamp(250px, 30vw, 400px), 1fr));
gap: 24px;
}
This single line creates a card layout that:
- Shows 1 column on narrow phones
- Shows 2 columns on tablets
- Shows 3+ columns on desktops
- All without a single
@mediarule
For forms and data display, you can use the same technique:
.form-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 16px;
}
Each form field pair (label + input) gets a minimum of 300px, wrapping gracefully on smaller screens.
CSS Grid Properties Cheat Sheet
Container Properties
| Property | Values | Description |
|---|---|---|
display | grid / inline-grid | Creates a grid container |
grid-template-columns | lengths, %, fr, repeat(), minmax() | Defines columns |
grid-template-rows | lengths, %, fr, repeat(), minmax() | Defines rows |
grid-template-areas | named area strings | Names grid areas |
gap | length | Space between items |
justify-items | start / end / center / stretch | Aligns items horizontally in cells |
align-items | start / end / center / stretch | Aligns items vertically in cells |
grid-auto-flow | row / column / dense | Controls auto-placement behavior |
Item Properties
| Property | Values | Description |
|---|---|---|
grid-column | start / end or span N | Item’s column placement |
grid-row | start / end or span N | Item’s row placement |
grid-area | name or start/end rows+columns | Item’s named area or combined placement |
justify-self | start / end / center / stretch | Overrides justify-items for this item |
align-self | start / end / center / stretch | Overrides align-items for this item |
Next Steps
CSS Grid transforms how you think about layout. Start by recreating a simple page layout (header, sidebar, content, footer) with named grid areas. Then experiment with auto-fit and minmax for responsive card layouts. Once you’re comfortable, try overlapping elements and dashboard designs.
For quick JSON formatting of your grid data or configuration files, try the JSON formatter on Devs2.org. And if you need to indent or beautify your CSS code, the text beautifier can help keep your stylesheets clean and readable.
Conclusion
CSS Grid is not just another layout tool—it’s a paradigm shift in how we think about web layouts. It turns complex, multi-column designs into clean, readable, and maintainable CSS. Combined with Flexbox for component-level work, Grid gives you everything you need to create any layout you can imagine.
The responsive patterns alone (auto-fit, minmax, named areas) save countless hours of media query writing and debugging. Whether you’re building a simple blog, a complex dashboard, or a magazine-style landing page, CSS Grid is the foundation you’ve been looking for.
Start using Grid today. Your future self will thank you when you need to rearrange a layout and all you have to do is change a few lines in grid-template-areas.