VS
Frontend Development

CSS Grid vs Flexbox: When to Use Which

Mayur Dabhi
Mayur Dabhi
February 19, 2026
16 min read

You build a row of product cards with display: flex; flex-wrap: wrap. It looks fine until the last row has two cards instead of four, and those two stretch across the whole width. You fiddle with flex-basis and max-width for twenty minutes, then someone replaces the whole thing with three lines of CSS Grid and it just works. The opposite happens too: a nav bar wrestled into grid columns when Flexbox would've done it in one rule.

This post covers how the two actually differ, which one I reach for in common situations, how they fit together, and a couple of sizing gotchas that trip people up with both.

The Short Version

Flexbox lays things out along one axis (a row OR a column). CSS Grid handles rows AND columns at the same time. Most real pages use both.

Understanding the Core Difference

It comes down to dimensions. Flexbox works along a single axis, horizontal or vertical, and each line of items is sized on its own. Grid defines rows and columns together, so an item in row three lines up with the items above it.

FLEXBOX One-Dimensional Main Axis (flex-direction) CSS GRID Two-Dimensional Columns (Inline Axis) Rows (Block Axis)

Flexbox arranges items along one axis; Grid controls both rows and columns simultaneously

Side-by-Side Comparison

Flexbox

  • One-dimensional layout
  • Content-first approach
  • Items flow naturally
  • Good fit for components
  • Item size driven by content
  • Easy alignment on one axis

CSS Grid

  • Two-dimensional layout
  • Layout-first approach
  • Explicit placement
  • Good fit for page layouts
  • Track sizes defined up front
  • Items line up across rows

Flexbox in Practice

Flexbox earns its keep when you don't know how big things will be. A button label that might be "OK" or "Save and continue", a username of any length, a variable number of tags: flex distributes whatever space is left and lets items grow or shrink to fit. That's why it shows up mostly at the component level.

Basic Flexbox Setup

CSS
.flex-container {
  display: flex;
  
  /* Main axis direction */
  flex-direction: row;        /* row | row-reverse | column | column-reverse */
  
  /* Wrapping behavior */
  flex-wrap: wrap;            /* nowrap | wrap | wrap-reverse */
  
  /* Main axis alignment */
  justify-content: center;    /* flex-start | flex-end | center | space-between | space-around | space-evenly */
  
  /* Cross axis alignment */
  align-items: center;        /* stretch | flex-start | flex-end | center | baseline */
  
  /* Multi-line alignment */
  align-content: stretch;     /* flex-start | flex-end | center | space-between | space-around | stretch */
  
  /* Gap between items */
  gap: 16px;
}

.flex-item {
  /* Growth factor */
  flex-grow: 1;               /* How much item should grow relative to others */
  
  /* Shrink factor */
  flex-shrink: 0;             /* How much item should shrink relative to others */
  
  /* Base size */
  flex-basis: 200px;          /* Initial size before growing/shrinking */
  
  /* Shorthand: grow shrink basis */
  flex: 1 0 200px;
  
  /* Individual alignment override */
  align-self: flex-end;
}

Flexbox Visual Guide

justify-content (Main Axis) flex-start center space-between space-around align-items (Cross Axis) stretch flex-start center flex-end

Flexbox alignment properties visualized

Flexbox Use Cases

Navigation Bars

Horizontal menus with flexible spacing between items

Card Components

Vertically stacked content with consistent alignment

Media Objects

Image with text content side-by-side

Equal Height Columns

Columns that stretch to match tallest sibling

When I Reach for Flexbox

Spreading items out along one axis, centering something, or building a component where items should grow or shrink with the space available.

Gotcha: Flex Items Refuse to Shrink

Flex items default to min-width: auto, so they won't shrink below the width of their content. That's why text-overflow: ellipsis "doesn't work" inside a flex row, or a long URL pushes the layout sideways on mobile. Add min-width: 0 (or overflow: hidden) to the item that should shrink. Grid has the same issue: 1fr means minmax(auto, 1fr), so a wide <pre> block or table can blow a column out. Use minmax(0, 1fr) when that happens.

CSS Grid in Practice

With Grid you describe the layout on the container first, then drop items into it. Columns and rows are defined together, so you get precise placement and alignment across both directions. I use it for page shells and for any component where things need to line up in columns.

Basic Grid Setup

CSS
.grid-container {
  display: grid;
  
  /* Define columns */
  grid-template-columns: 200px 1fr 200px;         /* Fixed, flexible, fixed */
  grid-template-columns: repeat(3, 1fr);           /* Three equal columns */
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); /* Responsive! */
  
  /* Define rows */
  grid-template-rows: auto 1fr auto;               /* Header, content, footer */
  
  /* Gap between cells */
  gap: 20px;                                       /* row-gap and column-gap */
  
  /* Named template areas */
  grid-template-areas:
    "header header header"
    "sidebar main aside"
    "footer footer footer";
}

.grid-item {
  /* Span multiple columns */
  grid-column: 1 / 3;          /* Start at line 1, end at line 3 */
  grid-column: span 2;         /* Span 2 columns from current position */
  
  /* Span multiple rows */
  grid-row: 1 / 4;             /* Start at line 1, end at line 4 */
  
  /* Place in named area */
  grid-area: header;
  
  /* Self alignment within cell */
  justify-self: center;        /* Horizontal alignment */
  align-self: center;          /* Vertical alignment */
}

Grid Template Areas

Named areas let you draw the layout as ASCII art right in the CSS. Rearranging the page for mobile becomes a matter of rewriting those strings instead of touching every item's placement.

Grid Template Areas - Holy Grail Layout HEADER grid-area: header NAV sidebar MAIN CONTENT grid-area: main ASIDE aside FOOTER

Classic "Holy Grail" layout using grid-template-areas

CSS - Holy Grail Layout
.holy-grail {
  display: grid;
  min-height: 100vh;
  gap: 16px;
  
  grid-template-columns: 200px 1fr 200px;
  grid-template-rows: auto 1fr auto;
  
  grid-template-areas:
    "header  header  header"
    "sidebar main    aside"
    "footer  footer  footer";
}

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

/* Responsive: Stack on mobile */
@media (max-width: 768px) {
  .holy-grail {
    grid-template-columns: 1fr;
    grid-template-areas:
      "header"
      "main"
      "sidebar"
      "aside"
      "footer";
  }
}

Auto-Fit and Minmax: Responsive Without Media Queries

This is the trick that fixes the card problem from the intro. auto-fit plus minmax() gives you a grid that picks its own column count, no media queries involved. Keep in mind the column counts in the comment below are rough: padding and gap eat into the width, so the real breakpoints land a bit differently. If you'd rather keep empty column slots instead of stretching the cards when there are only a few, use auto-fill.

CSS - Responsive Card Grid
.card-grid {
  display: grid;
  
  /* Magic responsive formula */
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  
  gap: 24px;
  padding: 24px;
}

/* 
  This creates a grid where:
  - Each card is minimum 280px wide
  - Cards grow equally to fill available space (1fr)
  - Grid automatically adjusts number of columns
  - No media queries needed!
  
  On a 1200px screen: 4 columns
  On a 900px screen:  3 columns  
  On a 600px screen:  2 columns
  On a 400px screen:  1 column
*/
Live Demo: auto-fit with minmax (resize your browser!)
1
2
3
4
5
6

Grid Use Cases

Page Layouts

Complex layouts with headers, sidebars, and footers

Image Galleries

Pinterest-style layouts with varied sizes

Data Tables

Aligned columns with consistent widths

Dashboard Layouts

Widgets of different sizes in a grid

Decision Guide: Grid or Flexbox?

When I'm unsure, I run through roughly these questions:

Question 1: Do you need to control both rows AND columns?
↓ Yes → Use Grid
↓ No, just one direction...
Question 2: Should items wrap to new lines and maintain grid alignment?
↓ Yes → Use Grid with auto-fit
↓ No, free-flowing is fine...
Question 3: Do items need to grow/shrink dynamically based on content?
↓ Yes → Use Flexbox
↓ Fixed sizes are okay...
Question 4: Are you building a component (nav, card) or a page layout?
Component: Flexbox is usually the right choice
Page Layout: Grid gives you more control

Using Grid and Flexbox Together

You don't have to pick one per project. A common split is Grid for the page structure and Flexbox for the components sitting in the grid cells.

Grid + Flexbox Together CSS Grid (Page Layout) Flexbox Nav Logo Grid Cell Nested Grid (Cards) Flexbox (card content) Flexbox (card content) Flexbox (card content) Footer (Flexbox for centering)

Page layout with Grid, components inside with Flexbox

CSS - Combined Layout
/* Page layout with Grid */
.page {
  display: grid;
  min-height: 100vh;
  grid-template-columns: 250px 1fr;
  grid-template-rows: auto 1fr auto;
  grid-template-areas:
    "header header"
    "sidebar main"
    "footer footer";
}

/* Navigation with Flexbox */
.header {
  grid-area: header;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0 24px;
}

.nav-links {
  display: flex;
  gap: 24px;
}

/* Card grid inside main area */
.main {
  grid-area: main;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 24px;
  padding: 24px;
}

/* Card content with Flexbox */
.card {
  display: flex;
  flex-direction: column;
  gap: 16px;
  padding: 20px;
  background: var(--bg-secondary);
  border-radius: 12px;
}

.card-header {
  display: flex;
  align-items: center;
  gap: 12px;
}

.card-footer {
  display: flex;
  justify-content: space-between;
  margin-top: auto; /* Push to bottom */
}

Common Patterns

Centering Content (The Classic Problem)

CSS - Flexbox Centering
.center-flexbox {
  display: flex;
  justify-content: center;  /* Horizontal */
  align-items: center;      /* Vertical */
  min-height: 100vh;
}
CSS - Grid Centering
.center-grid {
  display: grid;
  place-items: center;      /* Both axes at once! */
  min-height: 100vh;
}

/* Or */
.center-grid-alt {
  display: grid;
  place-content: center;
}

Sticky Footer

CSS - Sticky Footer with Grid
.page-wrapper {
  display: grid;
  grid-template-rows: auto 1fr auto;
  min-height: 100vh;
}

.header { /* auto height */ }
.main   { /* takes remaining space (1fr) */ }
.footer { /* auto height, always at bottom */ }

Equal-Height Cards in a Row

CSS - Equal Height with Flexbox
.card-row {
  display: flex;
  gap: 24px;
}

.card {
  flex: 1;                    /* Equal width */
  display: flex;
  flex-direction: column;
}

.card-body {
  flex: 1;                    /* Fills remaining space */
}

.card-footer {
  margin-top: auto;           /* Always at bottom */
}

Quick Reference Cheat Sheet

Use Case Recommended Why
Page layout (header, sidebar, main, footer) Grid Two-dimensional control needed
Navigation bar Flexbox Single row, flexible spacing
Card grid that wraps Grid auto-fit keeps alignment
Centering a single element Grid place-items: center is simplest
Items with varying sizes in a row Flexbox Content-based sizing
Form layout with labels/inputs Grid Aligned columns
Vertical stack with spacing Flexbox Simple, single axis
Pinterest-style masonry Grid grid-auto-rows with varying heights
Common Mistakes
  • Using Grid for everything: Not every layout needs two dimensions. A simple row is usually less code with Flexbox.
  • Margins instead of gap: Both Grid and Flexbox support gap, and it doesn't leave you with a stray margin on the last item.
  • Skipping minmax(): For responsive grids, minmax(250px, 1fr) saves you a pile of media queries.
  • Over-nesting: A flex container inside a flex container inside a grid cell is usually a sign one level could go.

When I'd Pick Each (and When I Wouldn't)

I default to Flexbox for anything that's a single row or column of stuff whose size depends on its content: nav bars, button groups, toolbars, a card's internal stack. I wouldn't use it for a wrapping card list where the last row needs to line up with the rows above. That's exactly the case where flex fights you and Grid doesn't.

I reach for Grid when items have to align in both directions: page shells, dashboards, forms with a label column and an input column, card grids. I'd skip it for a row of tags or chips whose count and widths vary a lot. Grid wants you to think in tracks, and a wrapping flex row handles that kind of content with less ceremony.

One thing to keep an eye on with Grid: if you rearrange items visually with grid-template-areas or order, the tab order and screen reader order still follow the HTML source. Moving the sidebar above the main content on mobile is fine visually, but check it with the keyboard before you ship. And if a layout looks broken and you can't tell why, turn on the Grid and Flex overlays in your browser's devtools. They show the actual tracks and free space, which usually explains the problem faster than reading the CSS.

CSS Grid Flexbox Layout Responsive Design Frontend
Mayur Dabhi

Mayur Dabhi

Full-stack developer passionate about clean code, modern web technologies, and sharing knowledge with the community.