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

1
2
3
4
5
6

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)

Sidebar
200px
Main
1fr
Aside
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

PropertyDescriptionExample Values
displayDefines grid containergrid, inline-grid
grid-template-columnsDefines column tracks1fr 1fr, repeat(3, 1fr)
grid-template-rowsDefines row tracks100px auto 1fr
gapSpace between items20px, 10px 20px
grid-template-areasNamed grid areas"header header" "main aside"
justify-itemsAlign items horizontallystart, center, end, stretch
align-itemsAlign items verticallystart, center, end, stretch

Item Properties

PropertyDescriptionExample Values
grid-columnItem’s column position1 / 3, span 2
grid-rowItem’s row position1 / 3, span 2
grid-areaNamed area or positionheader, 1 / 1 / 3 / 3
justify-selfAlign item horizontallystart, center, end
align-selfAlign item verticallystart, 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

Item 1
(2 cols)
Item 2
(2 cols × 2 rows)
Item 3
(2 rows)
4
5
6
7
8

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

Header
Main Content
Aside

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)

Item 1
Item 2
Item 3
Item 4
Item 5
Item 6

Auto-fit vs Auto-fill:

  • auto-fit – Collapses empty tracks and stretches items to fill space
  • auto-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?

ScenarioUse GridUse 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-fit and minmax() 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.