CSS Grid Layout: A Complete Visual Guide

Master CSS Grid with clear visual examples covering grid containers, tracks, areas, alignment, responsive patterns, and real-world layout techniques.

Hero image for CSS Grid Layout: A Complete Visual Guide

CSS Grid is the most powerful layout system ever added to CSS. With it, you can create complex two-dimensional layouts that were previously impossible without JavaScript or deeply nested markup. This guide will take you from the basics to advanced techniques.

What is CSS Grid?

CSS Grid is a two-dimensional layout system — it handles both rows and columns simultaneously. Compare this to Flexbox, which is primarily one-dimensional (either a row or a column).

Use Grid for page layouts and UI regions. Use Flexbox for component-level alignment and one-directional flows.

The Grid Container

Everything starts with display: grid:

.container {
  display: grid;

  /* Define 3 columns: fixed | flexible | auto */
  grid-template-columns: 200px 1fr auto;

  /* Define 2 rows */
  grid-template-rows: 60px 1fr;

  /* Gap between cells */
  gap: 1rem; /* row-gap + column-gap */
  column-gap: 2rem;
  row-gap: 1rem;
}

The fr Unit

The fr (fraction) unit represents a fraction of the available space after fixed sizes are allocated:

/* Three equal columns */
grid-template-columns: 1fr 1fr 1fr;

/* Sidebar + main + sidebar */
grid-template-columns: 250px 1fr 250px;

/* Ratio of 1:2:1 */
grid-template-columns: 1fr 2fr 1fr;

Defining Grid Areas

Named grid areas make layouts readable and maintainable:

.layout {
  display: grid;
  grid-template-areas:
    "header  header  header"
    "sidebar main    main  "
    "footer  footer  footer";
  grid-template-columns: 250px 1fr;
  grid-template-rows: auto 1fr auto;
  min-height: 100vh;
}

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

This creates a classic blog layout:

┌───────────────────────────────┐
│           HEADER              │
├──────────┬────────────────────┤
│ SIDEBAR  │       MAIN         │
│          │                    │
│          │                    │
├──────────┴────────────────────┤
│           FOOTER              │
└───────────────────────────────┘

Placing Items on the Grid

You can place items explicitly using line numbers:

.item {
  /* grid-column: start-line / end-line */
  grid-column: 1 / 3; /* Span from line 1 to line 3 */
  grid-column: 1 / -1; /* Span entire row */
  grid-column: span 2; /* Span 2 columns from current position */

  /* grid-row: start-line / end-line */
  grid-row: 2 / 4;

  /* Shorthand: row-start / column-start / row-end / column-end */
  grid-area: 2 / 1 / 4 / 3;
}

Repeat and Auto Functions

repeat()

Avoid repeating yourself when defining tracks:

/* ❌ Repetitive */
grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr;

/* ✅ Concise */
grid-template-columns: repeat(12, 1fr);

/* Mixed: 2 fixed columns then 3 flexible */
grid-template-columns: 200px 100px repeat(3, 1fr);

minmax()

Define a range for track sizes:

/* Column that's at least 200px but can grow */
grid-template-columns: minmax(200px, 1fr);

/* Row that's at least 100px but sizes to content */
grid-template-rows: minmax(100px, auto);

auto-fill and auto-fit

Create responsive grids without media queries:

/* auto-fill: Fill as many columns as fit, keeping empty tracks */
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));

/* auto-fit: Same but collapses empty tracks */
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));

This creates a responsive card grid that goes from 1 column on mobile to as many as fit on desktop:

Mobile (320px):    | Card |
Tablet (768px):    | Card | Card | Card |
Desktop (1440px):  | Card | Card | Card | Card | Card | Card |

Grid Alignment

Control how items are aligned inside their grid cells:

.container {
  /* Align all items along the row axis (horizontal) */
  justify-items: start | end | center | stretch;

  /* Align all items along the column axis (vertical) */
  align-items: start | end | center | stretch;

  /* Shorthand */
  place-items: center; /* align-items + justify-items */
}

.item {
  /* Override alignment for specific items */
  justify-self: start | end | center | stretch;
  align-self: start | end | center | stretch;
  place-self: center;
}

Aligning the Grid Itself

When the grid is smaller than the container:

.container {
  /* Distribute columns within the container */
  justify-content: start | end | center | stretch | space-around | space-between
    | space-evenly;

  /* Distribute rows within the container */
  align-content: start | end | center | stretch | space-around | space-between |
    space-evenly;
}

Real-World Patterns

Holy Grail Layout

.holy-grail {
  display: grid;
  grid-template:
    "header" auto
    "nav main aside" 1fr
    "footer" auto
    / 200px 1fr 200px;
  min-height: 100vh;
}

Responsive Card Grid

.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr));
  gap: 1.5rem;
}

The min(100%, 300px) prevents cards from being narrower than their container on very small screens.

Full-Bleed Layout

For a blog where most content is centered but some items (like images) should break out:

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

.content > * {
  grid-column: content;
}

.content > .wide {
  grid-column: wide;
}

.content > .full-bleed {
  grid-column: full;
}

Masonry Layout (CSS-native)

CSS masonry is in the specification but not widely supported yet. As a polyfill approach:

/* Two-column masonry with Flexbox */
.masonry {
  display: flex;
  flex-direction: column;
  flex-wrap: wrap;
  max-height: 1000px; /* Must set a height */
}

.masonry > * {
  width: calc(50% - 1rem);
}

Subgrid

Subgrid (now well-supported) lets nested grids participate in the parent grid:

.parent {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: auto auto;
  gap: 1rem;
}

/* Child spans all 3 columns and uses parent's column tracks */
.child {
  grid-column: span 3;
  display: grid;
  grid-template-columns: subgrid; /* Uses parent's 3 columns! */
}

This is incredibly useful for aligning items across cards:

.card-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
}

.card {
  display: grid;
  grid-row: span 3;
  grid-template-rows: subgrid; /* Title, description, and button all align! */
}

Debugging CSS Grid

Use browser DevTools to visualize your grid:

  1. Chrome/Edge: Open DevTools → Elements panel → click the grid badge
  2. Firefox: Superior grid inspector with named line visualization
  3. CSS: Add outline: 2px solid red to grid children temporarily
/* Quick debug helper */
.debug * {
  outline: 1px solid rgba(255, 0, 0, 0.3);
}

When to Use Grid vs Flexbox

SituationUse GridUse Flexbox
Overall page layout
Two-dimensional layouts
Content-driven sizing
Navigation bar
Card content layout
Centering a single itemEither
Vertical + horizontal control

Browser Support

CSS Grid has excellent browser support (97%+ globally). Subgrid is now supported in all modern browsers as of 2023.

/* Progressive enhancement for older browsers */
.layout {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
}

@supports (display: grid) {
  .layout {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  }
}

Conclusion

CSS Grid has fundamentally changed how we build web layouts. The key insights to take away:

  1. Grid is for 2D layouts, Flexbox is for 1D
  2. Named areas make your CSS self-documenting
  3. fr units + minmax() unlock responsive layouts without media queries
  4. auto-fit/auto-fill with minmax() is the go-to responsive card pattern
  5. Subgrid solves the alignment problems we’ve been fighting for years

Experiment in the browser, use the DevTools grid inspector, and refer to CSS-Tricks Grid Guide as a reference. Grid clicks quickly once you start using it in real projects.