DEV Community

Alex Chen
Alex Chen

Posted on

CSS Grid: The Complete Guide to Layout Mastery (2026)

CSS Grid: The Complete Guide to Layout Mastery (2026)

CSS Grid changed how we build layouts forever. No more floats, no more hacks — just clean, powerful layout control.

The Mental Model

CSS Grid = Two-dimensional layout system

Think of it as a spreadsheet:
┌─────┬─────┬─────┬─────┐
│     │     │     │     │  ← Rows (horizontal)
│  1  │  2  │  3  │  4  │
├─────┼─────┼─────┼─────┤
│     │     │     │     │
│  5  │  6  │  7  │  8  │    ← Columns (vertical)
├─────┼─────┼─────┼─────┤
│     │     │     │     │
│  9  │ 10  │ 11  │ 12  │
└─────┴─────┴─────┴─────┘

You define:
1. The grid container (display: grid)
2. Columns and rows (template)
3. Where items go (placement)
Enter fullscreen mode Exit fullscreen mode

Essential Properties

/* === Container: Define the grid === */
.dashboard {
  display: grid;

  /* Column definition */
  grid-template-columns: 250px 1fr 200px;       /* Fixed - Fluid - Fixed */
  grid-template-columns: repeat(4, 1fr);          /* 4 equal columns */
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); /* Responsive! */

  /* Row definition */
  grid-template-rows: auto 1fr auto;              /* Content-fit - Fill remaining - Content-fit */
  grid-template-rows: minmax(100px, auto);        /* At least 100px, grow if needed */

  /* Gap between cells */
  gap: 16px;                    /* Row + column gap */
  row-gap: 12px;                /* Row gap only */
  column-gap: 20px;             /* Column gap only */

  /* Alignment within the grid area */
  justify-items: start | center | end | stretch;   /* Horizontal alignment of items */
  align-items: start | center | end | stretch;      /* Vertical alignment of items */

  /* Entire grid content placement */
  justify-content: start | center | end | space-between | space-around | space-evenly;
  align-content: start | center | end | space-between | space-around | space-evenly;
}

/* === Items: Place them in the grid === */
.header {
  grid-column: 1 / -1;         /* Span all columns (from first to last) */
  grid-row: 1 / 2;             /* Row 1 only */
}

.sidebar {
  grid-column: 1 / 2;          /* First column only */
  grid-row: 2 / 4;             /* Span rows 2 and 3 */
}

.main-content {
  grid-column: 2 / 3;          /* Second column */
  grid-row: 2 / 4;             /* Span rows 2-3 */
}

/* Shorthand for both column AND row placement */
.featured {
  grid-area: 2 / 2 / 4 / 4;   /* row-start / col-start / row-end / col-end */
}
Enter fullscreen mode Exit fullscreen mode

Real-World Layouts

/* === Layout 1: Dashboard (classic admin layout) === */
.app-layout {
  display: grid;
  grid-template-columns: 260px 1fr;
  grid-template-rows: 64px 1fr auto;
  grid-template-areas:
    "sidebar header"
    "sidebar main"
    "sidebar footer";
  min-height: 100vh;
}

.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.footer { grid-area: footer; }

/* Mobile: stack everything vertically */
@media (max-width: 768px) {
  .app-layout {
    grid-template-columns: 1fr;
    grid-template-areas:
      "header"
      "main"
      "footer";
    .sidebar { display: none; } /* Or show as drawer */
  }
}

/* === Layout 2: Card Grid (responsive gallery) === */
.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 24px;
  padding: 16px;
}
/* Automatically adjusts number of columns based on available width!
   1200px viewport → 3 columns
   900px viewport → 2 columns
   350px viewport → 1 column */

/* === Layout 3: Holy Grail (header + footer + 3 columns) === */
.holy-grail {
  display: grid;
  grid-template-columns: 200px 1fr 180px;
  grid-template-rows: auto 1fr auto;
  grid-template-areas:
    "header header header"
    "nav    main   aside"
    "footer footer footer";
  min-height: 100vh;
}

/* === Layout 4: Magazine/News Layout === */
.magazine-layout {
  display: grid;
  grid-template-columns: 2fr 1fr;
  grid-template-rows: auto auto 1fr auto;
  grid-template-areas:
    "hero    hero"
    "featured sidebar"
    "articles sidebar"
    "footer  footer";
  gap: 32px;
}

.hero { grid-area: hero; }
.featured { grid-area: featured; }
.articles { 
  grid-area: articles; 
  display: grid;
  grid-template-columns: repeat(2, 1fr); /* Nested grid! */
  gap: 20px;
}
.sidebar { grid-area: sidebar; }
.footer { grid-area: footer; }

/* === Layout 5: Form alignment (no more tables!) === */
.form-grid {
  display: grid;
  grid-template-columns: 140px 1fr;
  gap: 16px;
  align-items: center;
  max-width: 500px;
}

.form-grid label { text-align: right; font-weight: 600; }
.form-grid input,
.form-grid select,
.form-grid textarea { width: 100%; }

.form-grid .full-width {
  grid-column: 1 / -1; /* Span across label + input columns */
}

@media (max-width: 480px) {
  .form-grid {
    grid-template-columns: 1fr; /* Stack on mobile */
  }
  .form-grid label { text-align: left; }
}
Enter fullscreen mode Exit fullscreen mode

Advanced Techniques

/* === Implicit Grid (auto-created rows/columns) === */
.grid-auto {
  display: grid;
  grid-template-columns: repeat(3, 100px);
  gap: 10px;
  /* If you place an item beyond defined columns/rows,
     Grid creates implicit ones automatically */
  grid-auto-columns: 80px;   /* Width of implicit columns */
  grid-auto-rows: minmax(60px, auto); /* Height of implicit rows */
  grid-auto-flow: row;       /* or 'column' — fill direction */
}

/* === Named Lines (more readable than numbers) === */
.named-lines {
  display: grid;
  grid-template-columns: [sidebar-start] 240px [sidebar-end main-start] 1fr [main-end aside-start] 200px [aside-end];
  grid-template-rows: [header-start] 70px [header-end content-start] 1fr [content-end];
}

.nav { grid-column: sidebar-start / sidebar-end; }
.content { grid-column: main-start / main-end; }

/* === Subgrid (child inherits parent's track definitions!) === */
.card {
  display: grid;
  grid-template-columns: 1fr 2fr;
  gap: 0;
}

.card-header {
  grid-column: 1 / -1; /* Spans full width */
  background: #f5f5f5;
  padding: 16px;
  /* Use subgrid to align with parent's rows */
  display: grid;
  grid-row: subgrid;
  grid-template-rows: subgrid; /* Inherits parent's row heights! */
}

/* === Overlapping Items (layering without absolute positioning) === */
.hero-section {
  display: grid;
  grid-template-columns: 1fr;
  grid-template-rows: 400px;
}

.hero-bg {
  grid-area: 1 / 1;
  background: url('hero.jpg') center/cover;
  z-index: 1;
}

.hero-overlay {
  grid-area: 1 / 1;
  background: rgba(0, 0, 0, 0.4);
  z-index: 2;
}

.hero-content {
  grid-area: 1 / 1;
  z-index: 3;
  color: white;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 40px;
}
/* All three occupy the same cell! Z-index controls visibility order. */

/* === Aspect Ratio Cards === */
.aspect-ratio-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
}

.aspect-card {
  aspect-ratio: 16 / 9; /* Maintains aspect ratio regardless of width */
  overflow: hidden;
  border-radius: 8px;
}

/* === Masonry-like effect (with limitations) === */
.masonry-workaround {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: 10px; /* Small base unit */
  gap: 16px;
}

.masonry-item:nth-child(1) { grid-row: span 25; } /* 250px tall */
.masonry-item:nth-child(2) { grid-row: span 35; } /* 350px tall */
.masonry-item:nth-child(3) { grid-row: span 20; } /* 200px tall */
/* Note: True masonry needs JS or the upcoming masonry spec */
Enter fullscreen mode Exit fullscreen mode

Grid vs Flexbox: When to Use Which

┌─────────────────────────────────────────────────┐
                  Use GRID when:                   
   Need 2D layout (rows AND columns)             
   Building overall page structure               
   Items need to overlap                         
   Complex alignment requirements                
   Example: dashboard, card grid, magazine       
├─────────────────────────────────────────────────┤
                 Use FLEXBOX when:                 
   Need 1D layout (row OR column)                
   Content-driven sizing                        
   Aligning items in a single line               
   Centering (the classic use case!)             
   Example: nav bar, form elements, button group 
└─────────────────────────────────────────────────┘

They work TOGETHER:
.grid-container { display: grid; }
.flex-inside-grid { display: flex; }  /* Totally fine! */
Enter fullscreen mode Exit fullscreen mode

What's your favorite Grid trick? What layout challenge are you still struggling with?

Follow @armorbreak for more practical developer guides.

Top comments (0)