CSS Grid

May 18, 2026
#css #web-development #grid #layout #responsive

CSS Grid is a two-dimensional layout system — it handles both rows and columns simultaneously. While Flexbox excels at laying out items in a single direction, Grid shines when you need to control placement in both dimensions at once: page layouts, card grids, dashboards, and anything with a structured arrangement.

The Basics

Like Flexbox, Grid works on a parent-child relationship. Set display: grid on the container, then define your columns and rows:

<div class="grid-container">
    <div class="item">1</div>
    <div class="item">2</div>
    <div class="item">3</div>
    <div class="item">4</div>
    <div class="item">5</div>
    <div class="item">6</div>
</div>
.grid-container {
    display: grid;
    grid-template-columns: 200px 200px 200px;
    gap: 16px;
}

This creates a 3-column grid where each column is 200px wide, with 16px gaps between items. Items flow into the grid automatically, filling row by row.

Defining Columns and Rows

Fixed sizes

.grid {
    display: grid;
    grid-template-columns: 200px 300px 200px;
    grid-template-rows: 100px 200px;
}

The fr unit (fractional)

fr distributes available space proportionally — it’s the most useful unit in Grid:

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

Mixing units

.layout {
    display: grid;
    grid-template-columns: 250px 1fr;  /* fixed sidebar, fluid content */
}

repeat()

Avoid repetition:

/* Instead of: 1fr 1fr 1fr 1fr */
.grid {
    grid-template-columns: repeat(4, 1fr);
}

/* Repeating patterns */
.grid {
    grid-template-columns: repeat(3, 1fr 2fr);  /* 1fr 2fr 1fr 2fr 1fr 2fr */
}

Gap (Spacing)

.grid {
    gap: 16px;              /* equal row and column gaps */
    gap: 20px 16px;         /* row-gap column-gap */
    row-gap: 20px;          /* only between rows */
    column-gap: 16px;       /* only between columns */
}

Placing Items

By default, items flow into the grid in order. But you can place them explicitly using grid lines (numbered starting at 1):

.header {
    grid-column: 1 / 4;    /* span from line 1 to line 4 (all 3 columns) */
}

.sidebar {
    grid-column: 1 / 2;    /* first column */
    grid-row: 2 / 4;       /* span rows 2 and 3 */
}

.content {
    grid-column: 2 / 4;    /* columns 2 and 3 */
}

Shorthand with span

.wide-item {
    grid-column: span 2;   /* take up 2 columns from current position */
}

.tall-item {
    grid-row: span 3;      /* take up 3 rows */
}

A Complete Page Layout

<div class="page">
    <header class="header">Header</header>
    <nav class="sidebar">Sidebar</nav>
    <main class="content">Content</main>
    <footer class="footer">Footer</footer>
</div>
.page {
    display: grid;
    grid-template-columns: 250px 1fr;
    grid-template-rows: 60px 1fr 50px;
    min-height: 100vh;
    gap: 0;
}

.header {
    grid-column: 1 / -1;   /* -1 means "last line" — spans full width */
}

.sidebar {
    grid-column: 1;
    grid-row: 2;
}

.content {
    grid-column: 2;
    grid-row: 2;
}

.footer {
    grid-column: 1 / -1;
}

Named Grid Areas

For complex layouts, named areas are more readable than line numbers:

.page {
    display: grid;
    grid-template-columns: 250px 1fr;
    grid-template-rows: 60px 1fr 50px;
    grid-template-areas:
        "header  header"
        "sidebar content"
        "footer  footer";
    min-height: 100vh;
}

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

The visual layout of the grid-template-areas value mirrors the actual page layout — making it easy to understand at a glance.

Alignment

Aligning items within their cells

.grid {
    /* Align all items */
    justify-items: center;   /* horizontal: start | end | center | stretch */
    align-items: center;     /* vertical: start | end | center | stretch */
}

/* Align a single item */
.special-item {
    justify-self: end;
    align-self: start;
}

Aligning the entire grid within its container

.grid {
    justify-content: center;  /* horizontal alignment of the grid itself */
    align-content: center;    /* vertical alignment of the grid itself */
}

Responsive Grids

auto-fill and auto-fit with minmax()

This is Grid’s killer feature for responsive design — no media queries needed:

.card-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
    gap: 24px;
}

This creates as many columns as will fit, each at least 300px wide, expanding to fill available space. As the viewport shrinks, columns drop to the next row automatically.

auto-fill vs auto-fit:

  • auto-fill — creates empty tracks if there’s extra space
  • auto-fit — collapses empty tracks, letting items stretch

For most card grids, auto-fill is what you want.

With media queries

For more control over breakpoints:

.grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 16px;
}

@media (min-width: 768px) {
    .grid {
        grid-template-columns: repeat(2, 1fr);
    }
}

@media (min-width: 1024px) {
    .grid {
        grid-template-columns: repeat(3, 1fr);
    }
}

Implicit vs Explicit Grid

The explicit grid is what you define with grid-template-columns and grid-template-rows. If there are more items than cells, Grid creates implicit rows automatically:

.grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    /* Only columns defined — rows are created implicitly */

    grid-auto-rows: 200px;  /* control the size of implicit rows */
}

minmax() works here too:

.grid {
    grid-auto-rows: minmax(100px, auto);  /* at least 100px, grow to fit content */
}

Grid vs Flexbox

They’re complementary, not competing:

Use Case Best Tool
Navigation bar Flexbox
Card grid Grid
Centering one item Flexbox
Full page layout Grid
Items in a row with wrapping Flexbox
Precise 2D placement Grid
Unknown number of items in one direction Flexbox

In practice, you’ll use both in the same page — Grid for the overall layout, Flexbox for components within it.

Common Patterns

Equal-height cards

.card-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 24px;
}

.card {
    display: flex;
    flex-direction: column;
}

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

Holy grail layout

.layout {
    display: grid;
    grid-template: 
        "header header header" 60px
        "left   main   right" 1fr
        "footer footer footer" 50px
        / 200px 1fr 200px;
    min-height: 100vh;
}

Overlapping items

Grid items can occupy the same cells — useful for image overlays:

.hero {
    display: grid;
    grid-template: 1fr / 1fr;  /* single cell */
}

.hero img,
.hero .overlay {
    grid-area: 1 / 1;  /* both in the same cell */
}

.hero .overlay {
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(0, 0, 0, 0.5);
    color: white;
}

What’s Next

With Flexbox and Grid in your toolkit, you can build virtually any layout. From here, explore CSS Responsive Design to learn media queries and mobile-first approaches, or jump into JavaScript DOM Manipulation to make your layouts interactive.