🔲

CSS Grid

Complete CSS Grid reference — tracks, placement, alignment, template areas and real-world layout patterns

Defining the Grid

Set up columns, rows and track sizes

css·Enable grid
.container {
  display: grid;        /* block-level grid */
}

.container-inline {
  display: inline-grid; /* inline-level grid */
}
css·grid-template-columns & grid-template-rows
.container {
  /* Fixed track sizes */
  grid-template-columns: 200px 200px 200px;

  /* Fractional units — share available space */
  grid-template-columns: 1fr 2fr 1fr;

  /* Mixed units */
  grid-template-columns: 240px 1fr;
  grid-template-rows: 64px 1fr 48px;

  /* Named lines */
  grid-template-columns: [sidebar-start] 240px [sidebar-end main-start] 1fr [main-end];

  /* repeat() shorthand */
  grid-template-columns: repeat(3, 1fr);
  grid-template-columns: repeat(3, 200px 1fr); /* alternating pattern */
}
css·repeat() with auto-fill and auto-fit
/* auto-fill: create as many tracks as fit, keep empty tracks */
.grid {
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
}

/* auto-fit: same but collapses empty tracks, items stretch to fill */
.grid {
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
}

/* Result: responsive columns with NO media queries
   Items wrap naturally when container is too narrow */
css·minmax(), min() and max() track sizing
.container {
  /* minmax(min, max) — track is at least min, at most max */
  grid-template-columns: minmax(200px, 1fr) 2fr;

  /* min-content / max-content */
  grid-template-columns: min-content 1fr max-content;

  /* fit-content(value) — like max-content but capped */
  grid-template-columns: fit-content(300px) 1fr;
}

/* Responsive sidebar that won't go below 200px or above 300px */
.layout {
  grid-template-columns: minmax(200px, 300px) 1fr;
}
css·gap — gutters between tracks
.container {
  gap: 16px;           /* equal row and column gap */
  gap: 24px 16px;      /* row-gap column-gap */
  row-gap: 24px;
  column-gap: 16px;
}
css·Implicit grid — auto rows and columns
/* Explicit grid: tracks you define with grid-template-* */
/* Implicit grid: auto-created tracks for items that overflow */

.container {
  grid-template-columns: repeat(3, 1fr);

  /* Control size of auto-created rows */
  grid-auto-rows: 200px;
  grid-auto-rows: minmax(100px, auto); /* min 100px, grows with content */

  /* Control direction items are auto-placed */
  grid-auto-flow: row;    /* default: fill rows first */
  grid-auto-flow: column; /* fill columns first */
  grid-auto-flow: row dense; /* fill gaps with smaller items */
}

Template Areas

Name regions of the grid for readable layouts

css·grid-template-areas
.page {
  display: grid;
  grid-template-columns: 240px 1fr;
  grid-template-rows: 64px 1fr 48px;
  grid-template-areas:
    "header  header"
    "sidebar main"
    "footer  footer";
  min-height: 100vh;
}

.page header  { grid-area: header; }
.page aside   { grid-area: sidebar; }
.page main    { grid-area: main; }
.page footer  { grid-area: footer; }
css·Responsive template areas with media query
.page {
  display: grid;
  grid-template-columns: 1fr;
  grid-template-areas:
    "header"
    "main"
    "sidebar"
    "footer";
}

@media (min-width: 768px) {
  .page {
    grid-template-columns: 240px 1fr;
    grid-template-areas:
      "header  header"
      "sidebar main"
      "footer  footer";
  }
}

/* Use . to leave a cell empty */
.dashboard {
  grid-template-areas:
    "header header header"
    "nav    main   .     "
    "nav    footer footer";
}

Item Placement

Place and span items across specific grid lines and cells

css·grid-column and grid-row
.item {
  /* grid-column: start-line / end-line */
  grid-column: 1 / 3;    /* spans columns 1 and 2 */
  grid-row: 2 / 4;       /* spans rows 2 and 3 */

  /* span keyword */
  grid-column: 1 / span 2;  /* start at 1, span 2 tracks */
  grid-column: span 3;       /* span 3 tracks from auto position */

  /* Negative line numbers count from the end */
  grid-column: 1 / -1;      /* full width, regardless of column count */
  grid-row: 1 / -1;         /* full height */
}
css·grid-area shorthand for placement
/* grid-area: row-start / col-start / row-end / col-end */
.item {
  grid-area: 1 / 1 / 3 / 4; /* rows 1-2, columns 1-3 */
}

/* Or reference a named area */
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
css·Named grid lines for semantic placement
.container {
  grid-template-columns:
    [full-start] 16px
    [content-start] 1fr
    [content-end] 16px
    [full-end];

  grid-template-rows:
    [header-start] 64px [header-end body-start] 1fr [body-end];
}

/* Items reference names instead of numbers */
.breakout { grid-column: full-start / full-end; }
.content  { grid-column: content-start / content-end; }
.header   { grid-row: header-start / header-end; }

Alignment

Align the grid and items within their cells

css·justify-items & align-items — all cells
/* justify-items: inline axis (horizontal) */
/* align-items:   block axis (vertical)   */

.container {
  justify-items: stretch; /* default: fill cell width */
  justify-items: start;
  justify-items: end;
  justify-items: center;

  align-items: stretch;   /* default: fill cell height */
  align-items: start;
  align-items: end;
  align-items: center;
  align-items: baseline;

  /* Shorthand */
  place-items: center;           /* align then justify */
  place-items: start end;        /* align-items justify-items */
}
css·justify-content & align-content — whole grid
/* Distributes the grid tracks within the container
   (only has effect if grid is smaller than container) */

.container {
  justify-content: start;         /* default */
  justify-content: end;
  justify-content: center;
  justify-content: stretch;
  justify-content: space-between;
  justify-content: space-around;
  justify-content: space-evenly;

  align-content: start;           /* default */
  align-content: end;
  align-content: center;
  align-content: space-between;
  align-content: space-around;

  /* Shorthand: align-content justify-content */
  place-content: center;
  place-content: space-between center;
}
css·justify-self & align-self — single item
/* Override container alignment for one item */
.item {
  justify-self: start;
  justify-self: end;
  justify-self: center;
  justify-self: stretch; /* default */

  align-self: start;
  align-self: end;
  align-self: center;
  align-self: stretch;   /* default */

  /* Shorthand: align-self justify-self */
  place-self: center;
  place-self: end start;
}

Layout Patterns

Battle-tested grid recipes for real interfaces

css·Responsive card grid — no media queries
.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 24px;
}

/* Cards automatically wrap at 280px minimum width.
   1 col on mobile, 2–3 on tablet, 4+ on desktop — zero media queries. */
css·Classic page layout — header, sidebar, main, footer
.page {
  display: grid;
  grid-template-columns: 260px 1fr;
  grid-template-rows: auto 1fr auto;
  grid-template-areas:
    "header  header"
    "sidebar main  "
    "footer  footer";
  min-height: 100vh;
}

.page > header  { grid-area: header;  }
.page > aside   { grid-area: sidebar; }
.page > main    { grid-area: main;    }
.page > footer  { grid-area: footer;  }
css·The RAM pattern — Repeat Auto Minmax
/* Fluid columns that fill the row, then wrap.
   Items on the last row stretch to fill — use auto-fit for this. */

.ram {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr));
  gap: 16px;
}

/* min(100%, 320px) prevents overflow on very small screens */
css·Masonry-style layout (CSS only)
.masonry {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: 10px; /* small row unit for fine-grained control */
  gap: 16px;
}

/* Each item sets its row span via JS or a known ratio:
   item with 300px height → span ceil(300 / 10) = 30 rows */
.item-tall   { grid-row: span 30; }
.item-medium { grid-row: span 20; }
.item-short  { grid-row: span 15; }
css·Full-bleed layout with constrained content
/* Items default to content column.
   Use .full-bleed to break out to full width. */

.layout {
  display: grid;
  grid-template-columns:
    [full-start]    1fr
    [content-start] min(65ch, 100% - 48px)
    [content-end]   1fr
    [full-end];
}

.layout > * {
  grid-column: content; /* all children in content column */
}

.layout > .full-bleed {
  grid-column: full;    /* hero, images, banners break out */
  width: 100%;
}
css·Dashboard grid with featured item
.dashboard {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-auto-rows: minmax(160px, auto);
  gap: 16px;
}

/* Featured card spans 2 columns and 2 rows */
.card--featured {
  grid-column: span 2;
  grid-row: span 2;
}

/* Wide stat bar spans full width */
.card--wide {
  grid-column: 1 / -1;
}
css·Centered content with sidebar
/* Sidebar on left, centered constrained content on right */
.layout {
  display: grid;
  grid-template-columns: 280px 1fr;
  gap: 32px;
  max-width: 1280px;
  margin-inline: auto;
  padding-inline: 24px;
}

.sidebar {
  position: sticky;
  top: 80px;
  align-self: start;  /* sticky needs this — don't stretch */
  height: fit-content;
}

.content {
  max-width: 72ch;
}

Subgrid

Let nested elements participate in the parent grid

css·subgrid — align nested content to parent tracks
/* Without subgrid, nested grids are independent */
/* With subgrid, children inherit parent grid tracks   */

.parent {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
}

/* Card spans 1 column but uses subgrid for its rows */
.card {
  display: grid;
  grid-row: span 3;
  grid-template-rows: subgrid; /* inherit parent's row tracks */
}

/* Now all cards' title/body/footer align across columns */
.card__title  { grid-row: 1; }
.card__body   { grid-row: 2; }
.card__footer { grid-row: 3; margin-top: auto; }
css·subgrid on both axes
.parent {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: auto auto auto;
  gap: 16px 24px;
}

.item {
  grid-column: span 2;
  grid-row: span 2;

  display: grid;
  grid-template-columns: subgrid; /* use parent's 2 spanned columns */
  grid-template-rows: subgrid;    /* use parent's 2 spanned rows */
}

/* Children of .item snap to the grandparent grid lines */

Gotchas & Tips

Grid edge cases, browser quirks and practical tips

css·fr vs % — don't mix with gap
/* % tracks include the gap in calculations → can overflow */
.bad {
  grid-template-columns: 50% 50%; /* overflows when gap is added */
  gap: 16px;
}

/* fr tracks exclude the gap automatically → always correct */
.good {
  grid-template-columns: 1fr 1fr; /* gap is subtracted before fr is applied */
  gap: 16px;
}
css·min-width: 0 — prevent overflow in grid items
/* Grid items default to min-width: auto, which respects content size.
   This can cause overflow with long words, code blocks, or flex children. */

/* Fix: set min-width: 0 on the grid item */
.grid-item {
  min-width: 0;     /* allows item to shrink below content size */
  overflow: hidden; /* or overflow-wrap: break-word for text */
}

/* Same issue exists for min-height on row-spanning items */
.grid-item-tall {
  min-height: 0;
}
css·auto vs 1fr — when to use each
/* auto: track sizes to fit its content */
/* 1fr:  track takes a fraction of the *remaining* free space */

/* Sidebar auto, main flexible */
.layout {
  grid-template-columns: auto 1fr; /* sidebar hugs content, main fills rest */
}

/* All equal regardless of content */
.equal {
  grid-template-columns: repeat(3, 1fr); /* each column is exactly 1/3 */
}

/* Header row auto-sizes, body fills remaining height */
.page {
  grid-template-rows: auto 1fr auto; /* header, main, footer */
  height: 100vh;
}
css·Debugging grid with DevTools
/* Chrome / Firefox both have visual grid overlays */

/* Quick debug: show grid lines with outline */
.container * {
  outline: 1px solid rgba(255, 0, 0, 0.3);
}

/* Log grid info in JS */
const el = document.querySelector('.grid');
const style = getComputedStyle(el);
console.log(style.gridTemplateColumns);
console.log(style.gridTemplateRows);

/* Firefox: Layout panel → Grid overlay → show line numbers
   Chrome:  Elements panel → Layout tab → Grid overlays */
css·Grid vs Flexbox — when to use which
/*
  Use GRID when:
  ─ You need 2-dimensional layout (rows AND columns)
  ─ You want precise placement into named areas
  ─ You're designing the layout first (layout-in)
  ─ Items should align to a shared grid regardless of content
  Examples: page layouts, dashboards, card grids, image galleries

  Use FLEXBOX when:
  ─ You need 1-dimensional layout (row OR column)
  ─ Items should size themselves based on their content
  ─ You're distributing space among unknown items (content-out)
  Examples: navbars, toolbars, button groups, media objects

  They complement each other — use grid for the macro layout,
  flexbox for the micro components inside grid areas.
*/