DevToolBoxGRATIS
Blogg

CSS Grid Guide: Complete Layout Tutorial with Flexbox Comparison

13 min readby DevToolBox
TL;DR
  • CSS Grid is two-dimensional; Flexbox is one-dimensional
  • The fr unit distributes free space proportionally
  • Use grid-template-areas for visual, named layouts
  • minmax() + auto-fit enables responsive grids with zero media queries
  • Subgrid solves cross-card alignment problems
  • Grid and Flexbox complement each other — use both

CSS Grid Layout is the most powerful layout system in CSS. It is a two-dimensional grid-based system, meaning it handles both columns and rows simultaneously. Unlike Flexbox, which deals with a single dimension at a time, Grid enables you to build complex web layouts with precise control over where every element is placed. This complete guide covers everything from fundamentals to advanced techniques including Flexbox comparison, real-world patterns, and debugging tips.

CSS Grid gained native browser support across all major browsers in 2017 and has become the go-to method for building dashboards, photo galleries, magazine-style pages, pricing tables, and full-page layouts. Mastering CSS Grid is a core skill for modern front-end development.

1. CSS Grid Basics: Enabling Grid Layout

To create a grid container, set display: grid or display: inline-grid on a parent element. All direct children automatically become grid items.

/* Block-level grid container */
.container {
  display: grid;
}

/* Inline grid container */
.container {
  display: inline-grid;
}

/* Children become grid items automatically */
.container > * {
  /* These are now grid items */
}

grid-template-columns and grid-template-rows

These properties define the number and size of grid tracks. You can mix any CSS length units, percentages, and the powerful fr fractional unit.

/* Three equal columns */
.grid {
  display: grid;
  grid-template-columns: 200px 200px 200px;
}

/* Three columns: fixed, flexible, fixed */
.grid {
  display: grid;
  grid-template-columns: 200px 1fr 200px;
}

/* Two rows: header 80px, content fills rest */
.grid {
  display: grid;
  grid-template-rows: 80px 1fr;
  height: 100vh;
}

/* Named grid lines for easier placement */
.grid {
  display: grid;
  grid-template-columns: [sidebar-start] 250px [sidebar-end content-start] 1fr [content-end];
}

The fr Unit: Fractional Space

The fr unit represents one fraction of the available free space in the grid container. The browser calculates fr values after fixed-size tracks (px, em, %) have been allocated. This allows truly flexible layouts without calculating percentages.

/* 1fr = all available space */
.grid { grid-template-columns: 1fr; }

/* Equal columns (each gets 1/3 of space) */
.grid { grid-template-columns: 1fr 1fr 1fr; }

/* Middle column is twice as wide */
.grid { grid-template-columns: 1fr 2fr 1fr; }

/* Mixed: fixed sidebar, flexible content */
.grid { grid-template-columns: 300px 1fr; }

/* Three equal columns + one double-width */
.grid { grid-template-columns: 1fr 1fr 2fr 1fr; }
/* Total: 5 parts — each 1fr = 20%, 2fr = 40% */
# grid-template-columns: 1fr 2fr 1fr visualized
┌──────────┬────────────────────┬──────────┐
│ 1fr │ 2fr │ 1fr │
│ ~25% │ ~50% │ ~25% │
└──────────┴────────────────────┴──────────┘

repeat()

The repeat() function avoids repeating the same track definition. The first argument is the number of repetitions (or the keywords auto-fill / auto-fit), the second is the track size.

/* 3 equal columns — verbose */
.grid { grid-template-columns: 1fr 1fr 1fr; }

/* 3 equal columns — with repeat() */
.grid { grid-template-columns: repeat(3, 1fr); }

/* 12-column grid (like Bootstrap) */
.grid { grid-template-columns: repeat(12, 1fr); }

/* Mixed: 2 fixed sidebar + repeat columns */
.grid { grid-template-columns: 200px repeat(3, 1fr) 200px; }

/* Responsive: as many 200px columns as fit */
.grid { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }

2. Grid Placement: Controlling Item Positions

By default, grid items are placed automatically in source order. But you can use grid-column, grid-row, and grid-area to precisely control each element's position and span.

grid-column & grid-row

/* grid-column: start / end (line numbers) */
.item {
  grid-column: 1 / 3;   /* spans columns 1 to 3 (2 columns wide) */
  grid-row: 1 / 2;      /* occupies row line 1 to 2 (1 row tall) */
}

/* Using span keyword */
.item {
  grid-column: 2 / span 2;  /* starts at line 2, spans 2 columns */
  grid-row: span 3;          /* spans 3 rows from auto-placed position */
}

/* Negative values count from the end */
.item {
  grid-column: 1 / -1;  /* full width across all columns */
  grid-row: 2 / -1;     /* from row 2 to the last row line */
}

/* Shorthand: grid-column is grid-column-start / grid-column-end */
.item { grid-column: 1 / 3; }
/* equivalent to: */
.item {
  grid-column-start: 1;
  grid-column-end: 3;
}

grid-area

grid-area is shorthand for grid-row-start / grid-column-start / grid-row-end / grid-column-end, and can also reference a name from named template areas.

/* Longhand equivalent */
.item {
  grid-area: 1 / 1 / 3 / 3;
  /* row-start=1, col-start=1, row-end=3, col-end=3 */
}

/* Named area reference (see grid-template-areas below) */
.header  { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main    { grid-area: main; }
.footer  { grid-area: footer; }

3. Named Grid Lines and Template Areas

grid-template-areas is one of the most intuitive features in CSS Grid. It lets you define your layout using string names, creating an ASCII-art-like visual representation of your layout directly in CSS.

/* Holy Grail layout with named areas */
.page {
  display: grid;
  grid-template-columns: 200px 1fr 200px;
  grid-template-rows: 60px 1fr 50px;
  grid-template-areas:
    "header  header  header"
    "sidebar main    aside"
    "footer  footer  footer";
  min-height: 100vh;
}

/* Assign items to areas */
.page-header  { grid-area: header; }
.page-sidebar { grid-area: sidebar; }
.page-main    { grid-area: main; }
.page-aside   { grid-area: aside; }
.page-footer  { grid-area: footer; }

/* Use period for empty cells */
.grid {
  grid-template-areas:
    "header header ."
    "sidebar main  main";
}

/* Responsive: collapse sidebar on mobile */
@media (max-width: 768px) {
  .page {
    grid-template-columns: 1fr;
    grid-template-areas:
      "header"
      "main"
      "sidebar"
      "aside"
      "footer";
  }
}
# Holy Grail Layout Visualization
┌────────────────────────────────────┐
│ HEADER (3 cols) │
├───────────┬────────────┬───────────┤
│ SIDEBAR │ MAIN │ ASIDE │
│ 200px │ 1fr │ 200px │
├───────────┴────────────┴───────────┤
│ FOOTER (3 cols) │
└────────────────────────────────────┘

4. Grid Alignment: justify and align Properties

CSS Grid provides a complete set of alignment properties that apply to both containers and individual items. Understanding the inline axis (horizontal) and block axis (vertical) is key to mastering alignment.

/* ─── Container-level alignment ─── */

/* justify-items: aligns items along inline (row) axis */
.grid {
  justify-items: start;    /* left-align all items */
  justify-items: end;      /* right-align all items */
  justify-items: center;   /* center all items */
  justify-items: stretch;  /* fill cell width (default) */
}

/* align-items: aligns items along block (column) axis */
.grid {
  align-items: start;      /* top-align all items */
  align-items: end;        /* bottom-align all items */
  align-items: center;     /* vertically center all items */
  align-items: stretch;    /* fill cell height (default) */
  align-items: baseline;   /* align by text baseline */
}

/* Shorthand: place-items = align-items / justify-items */
.grid {
  place-items: center;           /* center both axes */
  place-items: center stretch;   /* vertical center, horizontal stretch */
}

/* justify-content: distributes columns when grid is smaller than container */
.grid {
  justify-content: start | end | center | stretch |
                   space-between | space-around | space-evenly;
}

/* align-content: distributes rows when grid is smaller than container */
.grid {
  align-content: start | end | center | stretch |
                 space-between | space-around | space-evenly;
}

/* Shorthand: place-content = align-content / justify-content */
.grid { place-content: center; }

/* ─── Individual item alignment ─── */
.item {
  justify-self: start | end | center | stretch;
  align-self: start | end | center | stretch;
  place-self: center;  /* shorthand: align-self / justify-self */
}

gap (Gutters)

/* gap shorthand (row-gap / column-gap) */
.grid {
  gap: 16px;           /* same gap for rows and columns */
  gap: 20px 10px;      /* row-gap=20px, column-gap=10px */
}

/* Individual gap control */
.grid {
  row-gap: 24px;
  column-gap: 12px;
}

/* Old syntax (still works, but gap is preferred) */
.grid {
  grid-gap: 16px;
  grid-row-gap: 24px;
  grid-column-gap: 12px;
}

5. Auto Placement: grid-auto-flow and minmax()

grid-auto-flow

When grid items have no explicit placement, the browser uses the auto-placement algorithm. grid-auto-flow controls the direction and behavior of auto-placement.

/* Default: fill row by row, then add new rows */
.grid { grid-auto-flow: row; }

/* Fill column by column, then add new columns */
.grid { grid-auto-flow: column; }

/* Dense packing: fill gaps left by large items */
.grid { grid-auto-flow: row dense; }
.grid { grid-auto-flow: dense; }  /* same as row dense */

/* Control size of auto-generated rows/columns */
.grid {
  grid-auto-rows: 100px;        /* fixed height for implicit rows */
  grid-auto-rows: minmax(100px, auto); /* min 100px, grow to fit */
  grid-auto-columns: 200px;
}

minmax()

minmax(min, max) defines a size range for a track — setting both a minimum and maximum size. This is the key to responsive grids without media queries.

/* Column is at least 200px, can grow to fill space */
.grid {
  grid-template-columns: minmax(200px, 1fr);
}

/* Three columns: each at least 150px, at most equal thirds */
.grid {
  grid-template-columns: repeat(3, minmax(150px, 1fr));
}

/* Rows: at least 80px tall, expand for content */
.grid {
  grid-auto-rows: minmax(80px, auto);
}

/* The "holy grail" responsive card pattern */
.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 24px;
}
/* ↑ Creates as many 250px+ columns as fit, then stretches them equally */

auto-fill vs auto-fit

/* auto-fill: creates as many tracks as fit, keeps empty tracks */
.grid {
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
}

/* auto-fit: creates as many tracks as fit, COLLAPSES empty tracks */
.grid {
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}

/* Difference is visible when items < available columns:

   Container: 900px, min-item: 200px → 4 potential columns

   auto-fill (3 items):
   ┌──────┬──────┬──────┬──────┐
   │  #1  │  #2  │  #3  │      │  ← empty column preserved
   └──────┴──────┴──────┴──────┘

   auto-fit (3 items):
   ┌────────────┬────────────┬────────────┐
   │     #1     │     #2     │     #3     │  ← empty column collapsed
   └────────────┴────────────┴────────────┘
*/

6. Responsive Grid Patterns

Responsive Card Grid (Zero Media Queries)

/* Cards that automatically reflow at any screen size */
.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr));
  gap: 24px;
  padding: 24px;
}

/* The min(100%, 300px) prevents overflow on very small screens:
   - On wide screens: columns are at least 300px, max 1fr
   - On narrow screens: min(100%, 300px) = 100% → single column */

Magazine/Pinterest-style Layout

/* Masonry-like layout with varying row spans */
.magazine {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: 100px;
  gap: 16px;
}

/* Items take different row amounts */
.magazine .featured   { grid-row: span 3; grid-column: span 2; }
.magazine .tall       { grid-row: span 2; }
.magazine .wide       { grid-column: span 2; }
.magazine .normal     { /* defaults: 1 row, 1 col */ }

Dashboard Layout

/* Full dashboard with fixed sidebar */
.dashboard {
  display: grid;
  grid-template-columns: 240px 1fr;
  grid-template-rows: 64px 1fr;
  grid-template-areas:
    "nav     topbar"
    "nav     content";
  min-height: 100vh;
}

.dashboard-nav     { grid-area: nav; }
.dashboard-topbar  { grid-area: topbar; }
.dashboard-content { grid-area: content; }

/* Dashboard content with metric cards */
.dashboard-content {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: auto 1fr 1fr;
  gap: 20px;
  padding: 24px;
}

.metric-card    { /* 1 col × 1 row */ }
.chart-main     { grid-column: span 3; grid-row: span 2; }
.chart-side     { grid-row: span 2; }

@media (max-width: 1024px) {
  .dashboard-content {
    grid-template-columns: repeat(2, 1fr);
  }
  .chart-main { grid-column: span 2; }
}

@media (max-width: 768px) {
  .dashboard {
    grid-template-columns: 1fr;
    grid-template-areas:
      "topbar"
      "content";
  }
  .dashboard-nav { display: none; } /* or transform into drawer */
}

Photo Gallery Layout

/* Auto-filling image gallery */
.gallery {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  grid-auto-rows: 200px;
  gap: 4px;
}

.gallery img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Feature every 5th image */
.gallery .feature {
  grid-column: span 2;
  grid-row: span 2;
}

/* Landscape portrait mix with dense packing */
.gallery { grid-auto-flow: dense; }
.landscape { grid-column: span 2; }
.portrait  { grid-row: span 2; }

Pricing Table Layout

/* 3-column pricing table */
.pricing-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0;
  border-radius: 16px;
  overflow: hidden;
}

/* Highlight the middle (recommended) plan */
.pricing-grid .plan-featured {
  grid-row: 1 / -1;
  transform: scaleY(1.02);
  z-index: 1;
  box-shadow: 0 20px 40px rgba(0,0,0,0.15);
}

@media (max-width: 768px) {
  .pricing-grid {
    grid-template-columns: 1fr;
    gap: 16px;
  }
  .pricing-grid .plan-featured {
    transform: none;
    order: -1; /* show featured plan first on mobile */
  }
}

7. Subgrid — CSS Grid Level 2

Subgrid (grid-template-columns: subgrid or grid-template-rows: subgrid) allows a nested grid item to participate in and inherit track sizing from its ancestor grid. This solves the classic "cross-card alignment" problem where child elements inside different cards need to align across card boundaries. Subgrid landed in Firefox 71, Chrome 117, and Safari 16 — available in all modern browsers as of 2023.

/* PROBLEM: Card titles/descriptions don't align across cards */
.card-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
}
.card { display: flex; flex-direction: column; }
/* ↑ Each card has its own layout context — no cross-card alignment */

/* SOLUTION: Subgrid for cross-card alignment */
.card-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: auto auto 1fr auto; /* img, title, body, button */
  gap: 20px 20px;
}

.card {
  display: grid;
  grid-row: span 4;           /* card spans 4 rows */
  grid-template-rows: subgrid; /* inherit row tracks from parent! */
}

/* Now .card-image, .card-title, .card-body, .card-button
   in ALL cards share the SAME row tracks → perfect alignment */
.card-image  { grid-row: 1; }
.card-title  { grid-row: 2; }
.card-body   { grid-row: 3; }
.card-button { grid-row: 4; }

/* Subgrid can be used for columns too */
.nested-grid {
  display: grid;
  grid-column: 2 / 5;
  grid-template-columns: subgrid; /* inherits 3 parent columns */
}
# Subgrid solves cross-card alignment
Without subgrid: With subgrid:
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ [img] │ │ [img] │ │ [img] │ │ [img] │
│ Short │ │ A Very │ │ Short │ │ A Very │
│ Title │ │ Long │ │ Title │ │ Long │
│ Body... │ │ Title │ │ Body... │ │ Title │
│ [btn] │ │ Body... │ │ │ │ │
└──────────┘ │ [btn] │ │ [btn] │ │ Body... │
misaligned └──────────┘ └──────────┘ │ [btn] │
perfectly └──────────┘
aligned!

8. CSS Grid vs Flexbox: Complete Comparison

Grid and Flexbox are not competing technologies — they complement each other. Knowing when to use each is a hallmark of advanced CSS proficiency.

DimensionCSS GridFlexbox
DimensionsTwo-dimensional (rows + columns)One-dimensional (row OR column)
Best forPage layouts, complex grids, dashboardsNavbars, button groups, centering
Control fromPrimarily from containerBoth container and items
Content adaptationLayout-first, content fills tracksContent-first, items adapt to space
Overlapping itemsNative support (same grid area)Requires negative margin or position
Track alignmentPowerful (row and column alignment)Single-axis alignment
Responsive designAuto-placement + minmax() is very powerfulRequires media queries for wrapping control
Named layoutsgrid-template-areas supportedNot supported
Browser supportAll modern browsers (2017+)All modern browsers (2012+)

When to Choose Grid

/* Use Grid for:
   ✓ Full-page layouts (header/sidebar/main/footer)
   ✓ Card grids with consistent row heights
   ✓ Dashboard interfaces with multiple panels
   ✓ Magazine-style layouts with varying cell sizes
   ✓ Any layout where rows AND columns matter simultaneously
   ✓ When you need items to span multiple tracks
   ✓ Named area layouts for clarity and responsiveness
*/

/* Classic Grid use case: */
.page-layout {
  display: grid;
  grid-template-columns: 240px 1fr;
  grid-template-rows: 64px 1fr 48px;
  grid-template-areas:
    "sidebar header"
    "sidebar content"
    "sidebar footer";
  min-height: 100vh;
}

When to Choose Flexbox

/* Use Flexbox for:
   ✓ Navigation bars (horizontal list of links)
   ✓ Button groups and toolbars
   ✓ Centering a single element
   ✓ Card internals (icon + text layout)
   ✓ Form layouts with labels and inputs
   ✓ Any layout where items flow in one direction
   ✓ When content size should drive layout
*/

/* Classic Flexbox use case: */
.navbar {
  display: flex;
  align-items: center;
  gap: 16px;
}

.navbar .logo   { margin-right: auto; } /* push nav links to right */
.navbar .links  { display: flex; gap: 8px; }
.navbar .button { /* stays at far right */ }

Best Practice: Combining Grid and Flexbox

/* Use Grid for the outer page structure,
   Flexbox for inner component layouts */

/* OUTER: Grid layout */
.app {
  display: grid;
  grid-template-columns: 240px 1fr;
  grid-template-rows: 64px 1fr;
  grid-template-areas:
    "sidebar header"
    "sidebar main";
  min-height: 100vh;
}

/* INNER: Flexbox components */
.header {
  grid-area: header;
  display: flex;          /* flex for navbar */
  align-items: center;
  padding: 0 24px;
  gap: 16px;
}

/* Even deeper: Grid card layout → Flexbox card content */
.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 24px;
}

.card {
  display: flex;           /* flex for vertical card content */
  flex-direction: column;
}

.card-body { flex: 1; }   /* pushes footer to bottom */

9. CSS Grid with CSS Custom Properties

CSS custom properties (variables) work powerfully with CSS Grid, enabling configurable and themeable grid systems.

/* Define a configurable grid system */
:root {
  --grid-columns: 12;
  --grid-gap: 24px;
  --grid-max-width: 1200px;
  --sidebar-width: 280px;
  --card-min-width: 260px;
}

/* Base grid using variables */
.grid-container {
  display: grid;
  grid-template-columns: repeat(var(--grid-columns), 1fr);
  gap: var(--grid-gap);
  max-width: var(--grid-max-width);
  margin: 0 auto;
}

/* Responsive overrides via custom properties */
@media (max-width: 1024px) {
  :root { --grid-columns: 8; --grid-gap: 16px; }
}

@media (max-width: 768px) {
  :root { --grid-columns: 4; --grid-gap: 12px; }
}

/* Theming: dark mode changes gap/sizing */
@media (prefers-color-scheme: dark) {
  :root { --grid-gap: 20px; }
}

/* Component-level overrides */
.hero-grid {
  --grid-columns: 2;
  display: grid;
  grid-template-columns: repeat(var(--grid-columns), 1fr);
  gap: var(--grid-gap);
}

/* Dynamic inline grid (controlled by JS or inline styles) */
.dynamic-grid {
  display: grid;
  grid-template-columns: repeat(var(--cols, 3), 1fr);
}
/* In HTML: <div class="dynamic-grid" style="--cols: 4"> */

10. Browser Support and Fallbacks

CSS Grid has over 97% browser support across modern browsers as of 2024. For projects requiring legacy browser support, use feature detection and progressive enhancement.

/* Browser support (caniuse.com as of 2024):
   Chrome 57+    ✓ (2017)
   Firefox 52+   ✓ (2017)
   Safari 10.1+  ✓ (2017)
   Edge 16+      ✓ (2017)
   IE 11         partial (old syntax, -ms- prefix)
   Global support: ~97%+ */

/* Progressive enhancement: Flexbox fallback → Grid enhancement */
.container {
  display: flex;          /* Flexbox for old browsers */
  flex-wrap: wrap;
}

@supports (display: grid) {
  .container {
    display: grid;        /* Grid for modern browsers */
    grid-template-columns: repeat(3, 1fr);
  }
}

/* @supports for specific Grid features */
@supports (grid-template-areas: "a") {
  /* Named areas supported */
}

@supports (grid-template-rows: subgrid) {
  /* Subgrid supported */
  .card {
    grid-template-rows: subgrid;
  }
}

/* IE 11 fallback with -ms- prefix */
.ie-compat {
  display: -ms-grid;
  -ms-grid-columns: 200px 1fr;
  -ms-grid-rows: 60px 1fr;
}

/* Modern equivalent */
.ie-compat {
  display: grid;
  grid-template-columns: 200px 1fr;
  grid-template-rows: 60px 1fr;
}

11. Common Mistakes and Debugging Tips

Common Mistakes

/* MISTAKE 1: Setting display:grid on items (not container) */
.item { display: grid; } /* Wrong: this creates a new grid context */
.container { display: grid; } /* Correct */

/* MISTAKE 2: Forgetting grid-template-columns defaults to single column */
.container { display: grid; }
/* ↑ All items stack vertically — add grid-template-columns! */
.container {
  display: grid;
  grid-template-columns: repeat(3, 1fr); /* Now 3 columns */
}

/* MISTAKE 3: gap vs padding confusion */
.container { gap: 20px; }  /* Space between items */
.container { padding: 20px; } /* Space inside container (not between items) */

/* MISTAKE 4: Forgetting grid-column/row auto-placement resets */
/* When you explicitly place some items, auto-placed items fill remaining cells */

/* MISTAKE 5: Using % width on grid items (usually wrong) */
.item { width: 33%; } /* Wrong: grid already controls width via fr */
.item { } /* Correct: let grid track sizing do the work */

/* MISTAKE 6: grid-gap (old) vs gap (new) */
.grid { grid-gap: 16px; }  /* Old — still works but deprecated */
.grid { gap: 16px; }       /* Modern — preferred */

/* MISTAKE 7: Overlapping items without z-index */
.item-1 { grid-area: 1 / 1 / 3 / 3; }
.item-2 { grid-area: 2 / 2 / 4 / 4; } /* overlaps item-1 */
/* Add z-index to control stacking: */
.item-1 { z-index: 1; }
.item-2 { z-index: 2; }

Debugging Tips

/* TIP 1: Visualize grid with outline */
.container > * {
  outline: 2px solid red;
}

/* TIP 2: Background color different cells */
.item:nth-child(odd)  { background: rgba(100, 200, 255, 0.2); }
.item:nth-child(even) { background: rgba(255, 150, 100, 0.2); }

/* TIP 3: DevTools Grid Inspector
   - Firefox: Elements → grid badge → Layout panel
   - Chrome: Elements → grid badge → Layout panel
   Shows: line numbers, track sizes, area names, gaps */

/* TIP 4: Temporarily add grid-template-rows to see all rows */
.debug {
  grid-template-rows: 50px 50px 50px; /* see row boundaries */
}

/* TIP 5: Use grid-template-areas to debug layout visually */
.debug {
  grid-template-areas:
    "A A B"
    "C D B"
    "C E E";
  /* Every letter is a named area — easy to visualize */
}

12. Real-World Examples: Full Dashboard + Pricing Page

Full Dashboard HTML + CSS

/* ═══════════════════════════════════
   Complete Dashboard Grid Layout
   ═══════════════════════════════════ */

/* 1. App Shell */
.app {
  display: grid;
  grid-template-columns: var(--sidebar-width, 240px) 1fr;
  grid-template-rows: 64px 1fr;
  grid-template-areas:
    "sidebar topbar"
    "sidebar content";
  height: 100vh;
  overflow: hidden;
}

/* 2. Sidebar: flex column internally */
.sidebar {
  grid-area: sidebar;
  display: flex;
  flex-direction: column;
  overflow-y: auto;
}

/* 3. Top Bar: flex row */
.topbar {
  grid-area: topbar;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 24px;
}

/* 4. Content area: nested grid */
.content {
  grid-area: content;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: auto;
  grid-auto-rows: minmax(120px, auto);
  gap: 20px;
  padding: 24px;
  overflow-y: auto;
  align-content: start;
}

/* 5. KPI metric cards */
.metric-card { /* default: 1×1 */ }

/* 6. Main chart: spans 3 columns × 2 rows */
.chart-primary {
  grid-column: span 3;
  grid-row: span 2;
}

/* 7. Activity feed: 1 col × 2 rows */
.activity-feed {
  grid-row: span 2;
}

/* 8. Wide table: full width */
.data-table {
  grid-column: 1 / -1;
}
<!-- Dashboard HTML Structure -->
<div class="app">
  <nav class="sidebar">...</nav>
  <header class="topbar">...</header>
  <main class="content">
    <div class="metric-card">Revenue</div>
    <div class="metric-card">Users</div>
    <div class="metric-card">Orders</div>
    <div class="metric-card">Churn</div>
    <div class="chart-primary">Main Chart</div>
    <div class="activity-feed">Activity</div>
    <div class="data-table">Data Table</div>
  </main>
</div>

Responsive Pricing Table

/* Three-tier pricing: Starter / Pro / Enterprise */
.pricing {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 2px;
  background: #e2e8f0;
  border-radius: 16px;
  overflow: hidden;
  max-width: 900px;
  margin: 0 auto;
}

.pricing-plan {
  background: #fff;
  padding: 40px 32px;
  display: grid;
  grid-template-rows: auto auto auto 1fr auto;
  gap: 16px;
}

.pricing-plan.featured {
  background: #1e293b;
  color: #f8fafc;
  transform: scaleY(1.02);
  z-index: 1;
}

.plan-name    { font-size: 20px; font-weight: 700; }
.plan-price   { font-size: 48px; font-weight: 800; }
.plan-period  { font-size: 14px; opacity: 0.6; }
.plan-features{ /* fills remaining space */ }
.plan-cta     { /* sticks to bottom */ }

@media (max-width: 768px) {
  .pricing {
    grid-template-columns: 1fr;
    gap: 16px;
    background: transparent;
  }
  .pricing-plan.featured {
    transform: none;
    order: -1;
    border-radius: 12px;
  }
  .pricing-plan { border-radius: 12px; }
}
Key Takeaways
  1. display: grid enables two-dimensional layout; grid-template-columns/rows define tracks
  2. The fr unit distributes remaining space; repeat() avoids repetitive track definitions
  3. grid-template-areas creates readable, visual layout definitions
  4. minmax() + auto-fit is the best way to achieve responsive grids with zero media queries
  5. auto-fit collapses empty tracks (items stretch); auto-fill preserves empty tracks
  6. place-items: center is the shortcut for perfect centering in a grid cell
  7. Subgrid solves cross-card alignment (Chrome 117+, Firefox 71+, Safari 16+)
  8. Use Grid for page structure, Flexbox for component internals — combine both
  9. CSS custom properties make grid systems configurable and easy to theme
  10. Browser DevTools Grid Inspector is your best friend for debugging layouts

Frequently Asked Questions

What is CSS Grid and when should I use it?

CSS Grid is a two-dimensional layout system for the web. Use it when you need to control both rows and columns simultaneously — for example, full-page layouts, dashboards, photo galleries, and magazine-style designs. Unlike Flexbox (which is one-dimensional), Grid lets you place items precisely in both directions at once.

What does the fr unit mean in CSS Grid?

The fr (fraction) unit represents a fraction of the available free space in the grid container. For example, grid-template-columns: 1fr 2fr 1fr creates three columns where the middle column is twice as wide as the outer columns. The browser calculates fr after fixed-size tracks (px, em, %) are allocated.

What is the difference between auto-fill and auto-fit in CSS Grid?

Both create as many tracks as fit the container. The difference appears with fewer items than available tracks: auto-fill keeps empty tracks, preserving their space; auto-fit collapses empty tracks to zero width, allowing items to stretch and fill the container. Use auto-fit for responsive card grids and auto-fill when you want to maintain a consistent column count.

How do grid-column and grid-row shorthand properties work?

grid-column is shorthand for grid-column-start / grid-column-end, and grid-row is shorthand for grid-row-start / grid-row-end. You can use line numbers (grid-column: 1 / 3), named lines, or the span keyword (grid-column: span 2). Negative values count from the end of the explicit grid, so grid-column: 1 / -1 spans the full width.

What are CSS Grid named template areas?

Named template areas let you assign string names to grid cells using grid-template-areas on the container, then reference those names on items with grid-area. This creates a visual ASCII-art representation of your layout in CSS. Use a period (.) for empty cells. Named areas must be rectangular and cannot be repeated in non-adjacent cells.

What is subgrid in CSS Grid Level 2?

Subgrid (grid-template-columns: subgrid or grid-template-rows: subgrid) allows a nested grid item to participate in and inherit track sizing from its ancestor grid. This solves the classic "card alignment" problem where inner elements of different cards need to align across card boundaries. Subgrid is supported in all modern browsers as of 2023.

Should I use CSS Grid or Flexbox?

Use Grid for two-dimensional layouts where you need to control both rows and columns simultaneously (page layouts, dashboards, galleries). Use Flexbox for one-dimensional layouts where items flow in a single direction (navbars, button groups, centering). They complement each other — a Grid-based page layout with Flexbox-based components is the most common and effective combination.

How do I debug CSS Grid layouts?

Chrome, Firefox, and Edge DevTools all have dedicated CSS Grid inspectors. In Firefox, click the grid badge next to the container in the Elements panel to toggle a grid overlay. In Chrome, use the Layout panel to see grid line numbers and area names. The most common debugging technique is to add outline: 1px solid red to grid items or use background colors to visualize each cell.

Conclusion

CSS Grid is foundational to modern web layout. Master the core concepts — the fr unit, grid-template-areas, minmax(), auto-fit, and Subgrid — and you can build virtually any layout in just a few lines of CSS, without complex hacks or excessive media queries. Paired with CSS custom properties and modern DevTools, CSS Grid makes creating and maintaining complex layouts easier than ever before.

Remember the most important takeaway: Grid for page structure, Flexbox for component internals. Use them together and you have all the tools needed to build any modern web UI.

𝕏 Twitterin LinkedIn
Var detta hjälpsamt?

Håll dig uppdaterad

Få veckovisa dev-tips och nya verktyg.

Ingen spam. Avsluta när som helst.

Try These Related Tools

🌈CSS Gradient Generator🎨Color ConverterMDMarkdown to HTML

Related Articles

React Hooks komplett guide: useState, useEffect och Custom Hooks

Beharska React Hooks med praktiska exempel. useState, useEffect, useContext, useReducer, useMemo, useCallback, custom hooks och React 18+ concurrent hooks.

Next.js Performance Optimization: Core Web Vitals, Caching, and Edge

Master Next.js performance optimization. Complete guide with Core Web Vitals, image/font optimization, code splitting, Server Components, caching strategies, bundle analysis, ISR, Edge Runtime, and database optimization.

Web-prestandaoptimering: Core Web Vitals Guide 2026

Komplett guide till webbprestandaoptimering och Core Web Vitals. Forbattra LCP, INP och CLS med praktiska tekniker for bilder, JavaScript, CSS och caching.