The one-line rule

Flexbox is for one-dimensional layout — a row OR a column.Grid is for two-dimensional layout — rows AND columns simultaneously.

Flexbox: one direction at a time

Flexbox arranges items along a single axis — either horizontally (row) or vertically (column). The other axis is managed automatically. It excels at:

  • Navigation bars — items in a row, space between them
  • Centering a single item both horizontally and vertically
  • Button groups and tag lists
  • Distributing items with space-between or space-around
  • Any layout where the number of items is dynamic (unknown at write-time)
.nav {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

Flexbox is content-driven — the sizes and positions depend on the content. You start with items and arrange them.

Grid: two directions simultaneously

Grid defines a two-dimensional structure of rows and columns, then places items into that structure. It excels at:

  • Page-level layouts — header, sidebar, main content, footer
  • Card grids that need consistent column widths
  • Complex layouts where items must align in both dimensions
  • Any layout where the structure is defined independently of the content
.layout {
  display: grid;
  grid-template-columns: 240px 1fr;
  grid-template-rows: auto 1fr auto;
  min-height: 100vh;
}

Grid is layout-first — you define the structure, then place content into it.

The decision table

ScenarioUse
Navigation bar with items spaced evenlyFlexbox
Full page layout (sidebar + content)Grid
Card gallery with consistent column widthsGrid
Center a button inside a divFlexbox
Form label + input aligned in a rowFlexbox
Complex form with multiple columns and rowsGrid
Tag list that wraps to multiple linesFlexbox (with flex-wrap)
Photo mosaic with items spanning multiple cellsGrid

The case where you genuinely need both

A typical page layout uses Grid at the top level (page structure) and Flexbox inside components (navigation, card content, button groups). This is not a compromise — it is the intended usage:

/* Page layout: Grid */
.page {
  display: grid;
  grid-template-columns: 1fr 3fr;
}

/* Inside each card: Flexbox */
.card {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}

When either works (and which is simpler)

For a three-column equal-width layout, both work:

/* Grid approach */
.container { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; }

/* Flexbox approach */
.container { display: flex; gap: 1rem; }
.item { flex: 1; }

Grid is slightly cleaner here. But for responsive layouts where columns should wrap automatically, Grid's auto-fill and minmax() are significantly more powerful:

/* Responsive grid — no media queries needed */
.cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 1rem;
}

This creates as many columns as fit at 280px minimum, automatically wrapping to the next row. The equivalent in Flexbox requires more code.

Summary

  • Flexbox: one axis, content-driven, dynamic item counts — nav, buttons, centering
  • Grid: two axes, layout-driven, fixed structure — page layout, card grids, complex forms
  • Use Grid at the macro level, Flexbox inside components
  • For responsive grids without media queries, Grid's auto-fill + minmax() is the best tool

Generate visual CSS grid layouts with the free CSS grid generator — adjust columns, rows, and gaps visually and copy the CSS.