
How CSS Grid Works (With Real Examples)
CSS Grid is a powerful two-dimensional layout system that revolutionized how we build web layouts.
Unlike Flexbox, which works in one dimension, Grid allows you to control both rows and columns simultaneously,
making complex layouts simple and maintainable.
In this comprehensive guide, you’ll learn CSS Grid from the ground up with practical, real-world examples
you can use in your projects today.
What is CSS Grid?
CSS Grid is a layout system that divides a page into major regions or defines the relationship between
parts of an HTML control in terms of size, position, and layer. It creates a grid of rows and columns
where you can place items precisely.
Why Use CSS Grid?
- Two-dimensional control – Manage both rows and columns at once
- Simpler markup – No need for wrapper divs or clearfix hacks
- Responsive by default – Built-in features for responsive design
- Alignment made easy – Powerful alignment and spacing controls
- Overlapping elements – Items can overlap without absolute positioning
Grid Basics: Creating Your First Grid
To create a grid, you set display: grid on a container element.
This makes all direct children become grid items.
.container {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 20px;
}Live Example: Basic 3-Column Grid
Understanding Grid Terminology
Before diving deeper, let’s understand the key terms:
- Grid Container – The element with
display: grid - Grid Items – Direct children of the grid container
- Grid Line – The dividing lines that make up the structure
- Grid Track – The space between two grid lines (a row or column)
- Grid Cell – The space between two adjacent row and column lines
- Grid Area – The total space surrounded by four grid lines
Defining Columns and Rows
Using Fixed and Flexible Units
You can mix different units to create flexible layouts:
.container {
display: grid;
grid-template-columns: 200px 1fr 1fr;
gap: 15px;
}Live Example: Mixed Units (200px + 1fr + 1fr)
200px
1fr
1fr
The fr Unit
The fr unit represents a fraction of the available space in the grid container.
It’s incredibly useful for creating flexible, responsive layouts.
/* Each column gets equal space */
grid-template-columns: 1fr 1fr 1fr;
/* First column is 2x larger than others */
grid-template-columns: 2fr 1fr 1fr;The repeat() Function
Save time by using repeat() for repetitive patterns:
/* Instead of writing 1fr 1fr 1fr 1fr */
grid-template-columns: repeat(4, 1fr);
/* Create a pattern */
grid-template-columns: repeat(3, 1fr 2fr);Essential Grid Properties
Container Properties
| Property | Description | Example Values |
|---|---|---|
display | Defines grid container | grid, inline-grid |
grid-template-columns | Defines column tracks | 1fr 1fr, repeat(3, 1fr) |
grid-template-rows | Defines row tracks | 100px auto 1fr |
gap | Space between items | 20px, 10px 20px |
grid-template-areas | Named grid areas | "header header" "main aside" |
justify-items | Align items horizontally | start, center, end, stretch |
align-items | Align items vertically | start, center, end, stretch |
Item Properties
| Property | Description | Example Values |
|---|---|---|
grid-column | Item’s column position | 1 / 3, span 2 |
grid-row | Item’s row position | 1 / 3, span 2 |
grid-area | Named area or position | header, 1 / 1 / 3 / 3 |
justify-self | Align item horizontally | start, center, end |
align-self | Align item vertically | start, center, end |
Controlling Grid Item Placement
Spanning Multiple Columns or Rows
Make items span across multiple tracks using line numbers or the span keyword:
.item-1 {
grid-column: 1 / 3; /* From line 1 to line 3 */
grid-row: 1 / 2;
}
.item-2 {
grid-column: span 2; /* Span 2 columns */
grid-row: span 3; /* Span 3 rows */
}Live Example: Complex Layout with Spanning Items
(2 cols)
(2 cols × 2 rows)
(2 rows)
Using Named Grid Areas
Named areas make your grid layouts more readable and maintainable:
.container {
display: grid;
grid-template-columns: 1fr 3fr 1fr;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"header header header"
"sidebar main aside"
"footer footer footer";
gap: 20px;
min-height: 100vh;
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.aside { grid-area: aside; }
.footer { grid-area: footer; }Live Example: Complete Page Layout with Named Areas
Responsive Grid Layouts
Auto-fit and Auto-fill
Create responsive grids that automatically adjust the number of columns:
/* Items wrap to new rows as needed */
.container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 20px;
}Live Example: Responsive Grid (resize your browser)
Auto-fit vs Auto-fill:
auto-fit– Collapses empty tracks and stretches items to fill spaceauto-fill– Keeps empty tracks and maintains column count
Media Queries with Grid
Combine Grid with media queries for complete responsive control:
.container {
display: grid;
gap: 20px;
}
/* Mobile: 1 column */
@media (max-width: 768px) {
.container {
grid-template-columns: 1fr;
}
}
/* Tablet: 2 columns */
@media (min-width: 769px) and (max-width: 1024px) {
.container {
grid-template-columns: repeat(2, 1fr);
}
}
/* Desktop: 3 columns */
@media (min-width: 1025px) {
.container {
grid-template-columns: repeat(3, 1fr);
}
}Real-World Examples
Example 1: Photo Gallery
.gallery {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 15px;
padding: 20px;
}
.gallery img {
width: 100%;
height: 100%;
object-fit: cover;
border-radius: 8px;
}Example 2: Card Layout
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 30px;
}
.card {
display: grid;
grid-template-rows: 200px auto auto;
background: white;
border-radius: 10px;
overflow: hidden;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
}Example 3: Dashboard Layout
.dashboard {
display: grid;
grid-template-columns: 250px 1fr;
grid-template-rows: 60px 1fr;
grid-template-areas:
"sidebar header"
"sidebar main";
height: 100vh;
gap: 0;
}
.sidebar {
grid-area: sidebar;
background: #2c3e50;
}
.header {
grid-area: header;
background: white;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.main {
grid-area: main;
background: #f5f5f5;
padding: 30px;
overflow-y: auto;
}Example 4: Holy Grail Layout
.holy-grail {
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;
gap: 20px;
}
@media (max-width: 768px) {
.holy-grail {
grid-template-columns: 1fr;
grid-template-areas:
"header"
"nav"
"main"
"aside"
"footer";
}
}Advanced Grid Techniques
Nested Grids
Grid items can also be grid containers:
.outer-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 20px;
}
.inner-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 10px;
}Implicit vs Explicit Grid
The explicit grid is what you define with grid-template-columns and grid-template-rows.
The implicit grid is created automatically when items are placed outside the explicit grid.
.container {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-auto-rows: 100px; /* Control implicit rows */
gap: 10px;
}Dense Packing
Use grid-auto-flow: dense to fill holes in your grid:
.masonry {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
grid-auto-rows: 100px;
grid-auto-flow: dense;
gap: 10px;
}
.item-tall {
grid-row: span 2;
}
.item-wide {
grid-column: span 2;
}Grid vs Flexbox: When to Use Which?
| Scenario | Use Grid | Use Flexbox |
|---|---|---|
| Page layouts | ✅ Perfect for complex 2D layouts | ❌ Too limited |
| Navigation bars | ⚠️ Overkill for simple cases | ✅ Ideal for linear layouts |
| Card grids | ✅ Excellent with auto-fit | ✅ Also works well |
| Form layouts | ✅ Great for complex forms | ✅ Good for simple forms |
| Content that wraps | ✅ Precise control | ✅ Natural wrapping |
| Centering elements | ✅ Very easy | ✅ Also very easy |
General Rule:
Use Grid when you need to control layout in two dimensions (rows AND columns).
Use Flexbox when you’re working with one dimension (row OR column) and need flexible item sizing.
Common Grid Mistakes
1. Not Understanding the fr Unit
Problem: Mixing pixels and fr units incorrectly.
Solution: Remember that fr divides the remaining space after fixed units are accounted for.
/* 200px is subtracted first, then remaining space split in half */
grid-template-columns: 200px 1fr 1fr;2. Forgetting the Gap Property
Problem: Using margins on grid items instead of gap on the container.
Solution: Always use gap for consistent spacing.
/* ❌ BAD */
.grid-item {
margin: 10px;
}
/* ✅ GOOD */
.container {
gap: 20px;
}3. Overcomplicating Simple Layouts
Problem: Using Grid for everything when Flexbox would be simpler.
Solution: Choose the right tool. For navigation bars or simple rows, Flexbox is often better.
4. Not Testing Responsiveness
Problem: Grid looks great on desktop but breaks on mobile.
Solution: Use auto-fit, minmax(), and media queries to ensure responsive behavior.
5. Ignoring Implicit Grid
Problem: Not controlling automatically created rows/columns.
Solution: Use grid-auto-rows, grid-auto-columns, and grid-auto-flow.
Browser Support
CSS Grid has excellent browser support. All modern browsers fully support Grid, including:
- Chrome 57+
- Firefox 52+
- Safari 10.1+
- Edge 16+
Internet Explorer: IE 10-11 have partial support with the -ms- prefix and an older specification.
Consider using a fallback layout or graceful degradation for IE users.
Tools and Resources
Learning Resources
- Grid by Example – Comprehensive examples and patterns
- CSS Grid Generator – Visual grid layout creator
- Grid Garden – Interactive game to learn Grid
- MDN CSS Grid Layout – Complete technical documentation
Development Tools
- Firefox DevTools – Best-in-class Grid inspector
- Chrome DevTools – Grid overlay and inspection tools
- VS Code Extensions – CSS Grid snippets and helpers
Performance Considerations
CSS Grid is highly performant, but keep these tips in mind:
- Grid calculations are done by the browser’s layout engine – very efficient
- Avoid deeply nested grids when not necessary
- Use
auto-fitandminmax()for responsive layouts instead of many media queries - Grid doesn’t cause more reflows than other layout methods
- Combine with CSS containment (
contain: layout) for even better performance
Accessibility Best Practices
While CSS Grid is powerful for visual layout, always consider accessibility:
Visual Order vs Source Order
Grid allows you to reorder items visually, but screen readers follow the HTML source order.
Important: Only reorder content visually when the reading order remains logical.
If visual reordering changes the meaning, restructure your HTML instead.
/* Visual reordering should match logical reading order */
.container {
display: grid;
grid-template-columns: repeat(3, 1fr);
}
/* Be careful when using order property */
.item-3 {
order: 1; /* Moves visually but not in DOM */
}Keyboard Navigation
Ensure your grid layout supports keyboard navigation:
- Tab order should follow a logical flow
- Focus indicators should be clearly visible
- Interactive elements should maintain logical tab sequence
Responsive Text and Spacing
Ensure text remains readable and spacing is adequate across all grid layouts:
.container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
gap: clamp(1rem, 3vw, 2rem);
}
.grid-item {
padding: clamp(1rem, 2vw, 2rem);
font-size: clamp(1rem, 2vw, 1.25rem);
}CSS Grid Patterns and Recipes
Pattern 1: Responsive Image Grid with Aspect Ratio
.image-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 1rem;
}
.image-grid img {
width: 100%;
aspect-ratio: 16 / 9;
object-fit: cover;
border-radius: 8px;
}Pattern 2: Sidebar Layout That Breaks to Stack
.layout {
display: grid;
gap: 2rem;
}
/* Sidebar appears when there's enough space */
@media (min-width: 768px) {
.layout {
grid-template-columns: 250px 1fr;
}
}
/* Alternative: Using minmax for automatic stacking */
.layout-auto {
display: grid;
grid-template-columns: minmax(min-content, 250px) 1fr;
gap: 2rem;
}
@media (max-width: 767px) {
.layout-auto {
grid-template-columns: 1fr;
}
}Pattern 3: Featured Item Grid
.featured-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 1rem;
}
.featured {
grid-column: span 2;
grid-row: span 2;
}
@media (max-width: 768px) {
.featured-grid {
grid-template-columns: 1fr;
}
.featured {
grid-column: span 1;
grid-row: span 1;
}
}Pattern 4: RAM Layout (Repeat, Auto, Minmax)
/* The ultimate responsive grid pattern */
.ram-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(250px, 100%), 1fr));
gap: 2rem;
}
/* Ensures items never shrink below 250px
but can go smaller than that on mobile */Pattern 5: 12-Column Grid System
.grid-12 {
display: grid;
grid-template-columns: repeat(12, 1fr);
gap: 20px;
}
.col-4 { grid-column: span 4; }
.col-6 { grid-column: span 6; }
.col-8 { grid-column: span 8; }
.col-12 { grid-column: span 12; }
/* Responsive breakpoints */
@media (max-width: 768px) {
.col-4, .col-6, .col-8 {
grid-column: span 12;
}
}Pattern 6: Magazine-Style Layout
.magazine {
display: grid;
grid-template-columns: repeat(6, 1fr);
grid-auto-rows: 200px;
gap: 1rem;
}
.article-large {
grid-column: span 4;
grid-row: span 2;
}
.article-medium {
grid-column: span 2;
grid-row: span 2;
}
.article-small {
grid-column: span 2;
grid-row: span 1;
}
@media (max-width: 768px) {
.magazine {
grid-template-columns: 1fr;
}
.article-large,
.article-medium,
.article-small {
grid-column: span 1;
grid-row: span 1;
}
}Debugging CSS Grid
Using Browser DevTools
Modern browsers have excellent Grid debugging tools:
- Firefox: Best grid inspector with overlay lines, area names, and line numbers
- Chrome: Grid badge in Elements panel, overlay visualization
- Safari: Grid overlay in Web Inspector
Visual Debugging with CSS
Add temporary styles to see your grid structure:
/* Visualize grid structure */
.grid-debug {
background:
repeating-linear-gradient(
0deg,
transparent,
transparent 50px,
rgba(255, 0, 0, 0.1) 50px,
rgba(255, 0, 0, 0.1) 51px
),
repeating-linear-gradient(
90deg,
transparent,
transparent 50px,
rgba(0, 0, 255, 0.1) 50px,
rgba(0, 0, 255, 0.1) 51px
);
}
/* Outline all grid items */
.grid-debug > * {
outline: 2px solid red;
}Common Grid Issues and Fixes
Issue: Grid items overflow their container
Fix: Use minmax(0, 1fr) instead of just 1fr
/* Prevents overflow */
grid-template-columns: repeat(3, minmax(0, 1fr));Issue: Gaps collapse on mobile
Fix: Use responsive gap values
gap: clamp(10px, 3vw, 30px);Issue: Items don’t fill the entire cell
Fix: Items have align-self: stretch by default, but check for explicit height/width
.grid-item {
min-height: 100%;
min-width: 100%;
}Grid with Other CSS Features
Grid + Subgrid
Subgrid allows nested grids to align with parent grid tracks:
.parent-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 20px;
}
.child-grid {
display: grid;
grid-column: span 2;
grid-template-columns: subgrid; /* Inherits parent columns */
gap: 10px;
}Note: Subgrid has limited browser support. Check caniuse.com for current compatibility.
Grid + Container Queries
Combine Grid with container queries for truly modular components:
.card-container {
container-type: inline-size;
}
.card-grid {
display: grid;
gap: 1rem;
}
/* Adjust based on container size, not viewport */
@container (min-width: 500px) {
.card-grid {
grid-template-columns: repeat(2, 1fr);
}
}
@container (min-width: 800px) {
.card-grid {
grid-template-columns: repeat(3, 1fr);
}
}Grid + CSS Custom Properties
Make your grids dynamic with CSS variables:
:root {
--grid-columns: 3;
--grid-gap: 20px;
--grid-min-width: 250px;
}
.dynamic-grid {
display: grid;
grid-template-columns: repeat(var(--grid-columns), 1fr);
gap: var(--grid-gap);
}
/* Change values with JavaScript or media queries */
@media (max-width: 768px) {
:root {
--grid-columns: 1;
--grid-gap: 15px;
}
}Advanced Use Cases
Masonry-Style Layout (CSS Only)
.masonry {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
grid-auto-rows: 20px;
gap: 10px;
}
.masonry-item {
/* Items span based on content height */
grid-row-end: span var(--row-span);
}
/* Calculate row span with JavaScript */ Future: Native masonry layout is coming to CSS Grid with grid-template-rows: masonry,
currently available in Firefox behind a flag.
Overlap and Layering
Grid makes overlapping elements easy without absolute positioning:
.overlap-grid {
display: grid;
grid-template-columns: 1fr;
grid-template-rows: 1fr;
}
.background-layer {
grid-column: 1;
grid-row: 1;
z-index: 1;
}
.content-layer {
grid-column: 1;
grid-row: 1;
z-index: 2;
align-self: center;
justify-self: center;
}Asymmetric Layouts
.asymmetric {
display: grid;
grid-template-columns: 1fr 2fr 1fr 1fr;
grid-template-rows: repeat(4, 100px);
gap: 10px;
}
.item-1 {
grid-area: 1 / 1 / 3 / 3;
}
.item-2 {
grid-area: 1 / 3 / 2 / 5;
}
.item-3 {
grid-area: 2 / 3 / 4 / 4;
}
.item-4 {
grid-area: 2 / 4 / 5 / 5;
}
.item-5 {
grid-area: 3 / 1 / 5 / 3;
}Migration Tips: From Other Layouts to Grid
From Float Layouts
/* OLD: Float-based layout */
.sidebar {
float: left;
width: 30%;
margin-right: 3%;
}
.main {
float: left;
width: 67%;
}
.clearfix::after {
content: "";
display: table;
clear: both;
}
/* NEW: Grid-based layout */
.container {
display: grid;
grid-template-columns: 30% 67%;
gap: 3%;
}
/* Or better with fr units */
.container {
display: grid;
grid-template-columns: 1fr 2fr;
gap: 20px;
}From Bootstrap Grid to CSS Grid
/* Bootstrap approach */
Sidebar
Main
/* CSS Grid approach */
.container {
display: grid;
grid-template-columns: 1fr 2fr;
gap: 20px;
}
/* No extra row div needed! */
Sidebar
Main
Testing Your Grid Layouts
Checklist for Grid Testing
- ✅ Test with actual content, not just placeholder text
- ✅ Verify behavior with very long and very short content
- ✅ Check all major breakpoints (mobile, tablet, desktop)
- ✅ Test in different browsers (Chrome, Firefox, Safari, Edge)
- ✅ Verify keyboard navigation and focus order
- ✅ Test with browser zoom at 200%
- ✅ Check right-to-left (RTL) languages if applicable
- ✅ Validate with screen reader
Common Edge Cases
/* Handle very long words that might break layout */
.grid-item {
overflow-wrap: break-word;
word-break: break-word;
}
/* Prevent images from overflowing */
.grid-item img {
max-width: 100%;
height: auto;
}
/* Handle dynamic content */
.grid-item {
min-height: 0; /* Allow items to shrink */
min-width: 0; /* Prevent overflow */
}Final Thoughts and Best Practices
Key Takeaways
- Start simple – Begin with basic grids and add complexity as needed
- Use semantic HTML – Grid is for layout, not structure
- Mobile first – Design for small screens first, then enhance
- Leverage auto-fit – Let the browser do the responsive work
- Name your areas – Makes code more maintainable
- Combine with Flexbox – Use the right tool for each job
- Test extensively – Especially with real content
- Consider accessibility – Visual order should match reading order
When to Choose Grid Over Other Methods
Choose CSS Grid when you need:
- Two-dimensional layout control (rows AND columns)
- Precise item placement
- Overlapping elements without absolute positioning
- Responsive layouts that reflow content
- Complex page layouts (dashboards, magazines, portfolios)
- Asymmetric or irregular layouts
The Future of CSS Grid
CSS Grid continues to evolve with exciting features:
- Subgrid – Better alignment for nested grids (already in Firefox and Safari)
- Masonry layout – Native Pinterest-style layouts (in development)
- Container queries – Component-based responsive design (available in modern browsers)
- Grid Level 3 – Additional features and improvements being specified
Quick Reference Cheat Sheet
/* CONTAINER PROPERTIES */
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: 100px auto 100px;
grid-template-areas: "header header header"
"sidebar main aside"
"footer footer footer";
gap: 20px; /* or row-gap / column-gap */
justify-items: start; /* start | end | center | stretch */
align-items: start; /* start | end | center | stretch */
justify-content: start; /* start | end | center | stretch | space-around | space-between */
align-content: start; /* start | end | center | stretch | space-around | space-between */
grid-auto-flow: row; /* row | column | dense */
grid-auto-rows: 100px;
grid-auto-columns: 100px;
/* ITEM PROPERTIES */
grid-column: 1 / 3; /* or grid-column-start / grid-column-end */
grid-row: 1 / 3; /* or grid-row-start / grid-row-end */
grid-area: header; /* or row-start / col-start / row-end / col-end */
justify-self: start; /* start | end | center | stretch */
align-self: start; /* start | end | center | stretch */
/* COMMON PATTERNS */
repeat(3, 1fr) /* Repeat 3 equal columns */
repeat(auto-fit, minmax(200px, 1fr)) /* Responsive grid */
minmax(200px, 1fr) /* Flexible but not below 200px */
auto /* Size based on content */
min-content /* Smallest possible size */
max-content /* Largest possible size */
fit-content(500px) /* Content size, max 500px */Conclusion
CSS Grid is a game-changer for web layout. It simplifies complex layouts, reduces the need for
frameworks, and gives you precise control over your designs. While there’s a learning curve,
the investment pays off in cleaner code, better maintainability, and more creative possibilities.
Start by implementing simple grids in your projects, then gradually explore more advanced features
as you become comfortable. Use browser DevTools to visualize your grids, test thoroughly across
devices, and always keep accessibility in mind.
The future of web layout is here, and it’s a grid. Happy coding!
Want to learn more? Experiment with the examples in this article,
use browser DevTools to inspect real-world sites using Grid, and check out
Grid Garden for interactive learning.
