The short answer: use Flexbox when you're arranging items in a single row or column, and use CSS Grid when items need to line up in rows and columns at the same time. MDN puts it this way: flexbox was designed for layout in one dimension, either a row or a column, and grid was designed for two-dimensional layout. Most real pages use both, often nested inside each other. This guide gives you a checklist for choosing, copy-ready CSS for the most common layouts, and the patterns for combining them.

One dimension vs two dimensions

With Flexbox, you set a direction on the container and items flow along it. If they wrap onto a new line, each line is laid out on its own. MDN notes that when space is distributed, flexbox doesn't look at the placement of items in other rows, so items on different lines don't line up as columns.

With Grid, you define rows and columns (called tracks) on the container, and items are placed into the cells. Because every item belongs to both a row and a column, alignment holds in both directions.

MDN also describes the difference as content out versus layout in:

That's also where sizing happens. In Grid, most sizing is set on the container. In Flexbox, control over an item's size is set on the items themselves, with flex-grow, flex-shrink and flex-basis.

Decision checklist

If…Use
Items sit in a single row or a single columnFlexbox
Items need to line up in rows and columnsGrid
Each item's size should come from its contentFlexbox
You want to define the tracks first and place items into themGrid
Items should wrap, and uneven last rows are fineFlexbox with flex-wrap
Items should wrap and stay aligned in columnsGrid with repeat(auto-fill, …)
You're setting widths on flex items to make rows line upSwitch to Grid
Whole-page regions: header, sidebar, main, footerGrid
Navigation bars, toolbars, button groups, form rowsFlexbox

The most useful rule comes straight from MDN: if you're setting widths on flex items to make items in one row line up with the items above them, you should probably be using Grid. MDN also says there's no rule that Flexbox is for small components and Grid for large ones. A tiny component can be two-dimensional, and a large layout can be one-dimensional.

Copy-ready Flexbox examples

Navigation bar with the logo on the left

.nav {
  display: flex;
  align-items: center;   /* vertical centering on the cross axis */
  gap: 1rem;
}
.nav .logo {
  margin-right: auto;    /* pushes every link after it to the right */
}

An auto margin on a flex item takes up all the free space on that side, which is the easiest way to split a toolbar into a left group and a right group.

Tags or chips that wrap

.tags {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

Each tag is as wide as its text, and a line that's full wraps to the next. The rows won't form columns, and for tags you don't want them to.

Equal-width columns that share a row

.row {
  display: flex;
  gap: 1rem;
}
.row > * {
  flex: 1 1 0;   /* grow, shrink, start from zero so all are equal */
}

Copy-ready Grid examples

Responsive card grid with no media queries

.cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 16rem), 1fr));
  gap: 1.5rem;
}

The browser fits as many columns as it can, each at least 16rem wide, and stretches them to fill the row. Every card in a column has the same width, including on the last row. Wrapping the minimum in min(100%, 16rem) stops a column from overflowing on screens narrower than 16rem. MDN explains the alternative keyword: auto-fit behaves like auto-fill, except that empty repeated tracks are collapsed, so a short row of items stretches to fill the width instead of leaving empty columns.

Page layout with named areas

.page {
  display: grid;
  grid-template-columns: 1fr;
  grid-template-areas:
    "header"
    "main"
    "sidebar"
    "footer";
  gap: 1rem;
}
@media (min-width: 48rem) {
  .page {
    grid-template-columns: 16rem 1fr;
    grid-template-areas:
      "header  header"
      "sidebar main"
      "footer  footer";
  }
}
.page > header { grid-area: header; }
.page > nav    { grid-area: sidebar; }
.page > main   { grid-area: main; }
.page > footer { grid-area: footer; }

On small screens the regions stack; from 48rem up, the sidebar moves beside the main content. Only the template changes, not the HTML.

Center anything

.center {
  display: grid;
  place-items: center;
}

Flexbox can do this too, with justify-content: center and align-items: center. Grid needs one line.

Build a grid visually

Set columns, rows and gaps and copy the generated CSS, or convert pixel sizes to rem.

CSS Grid Generator → PX to REM Converter →

Combining Grid and Flexbox

The two aren't competing choices for a page; they nest. Any grid item can be a flex container, and any flex item can be a grid container. The most common combination is a grid of cards where each card uses Flexbox for its own content:

.cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 16rem), 1fr));
  gap: 1.5rem;
}
.card {
  display: flex;
  flex-direction: column;
}
.card .button {
  margin-top: auto;   /* pins the button to the bottom of every card */
}

Grid makes every card in a row the same height. Flexbox, inside each card, pushes the button to the bottom so the buttons line up even when the text above them is different lengths.

Lining up content across cards: subgrid

If the titles, text and footers inside neighboring cards should all line up with each other, a nested grid can borrow its parent's tracks with subgrid:

.card {
  display: grid;
  grid-row: span 3;
  grid-template-rows: subgrid;   /* title, body and footer rows shared across the row of cards */
}

Subgrid became Baseline in 2023, according to web.dev, with support in Chrome and Edge 117, Firefox 71 and Safari 16.

Things that work the same in both

Sizing tips

Use rem for track sizes, gaps and breakpoints so layouts scale when a reader changes their browser's font size. At the common 16px default, 16rem is 256px and 48rem is 768px. The PX to REM converter does the division for any base size, and why unit conversions don't always match explains the rounding you'll see with fractional values.

Layout is only half of a readable page; text and background colors matter just as much. The practical guide to WCAG color contrast covers the ratios to aim for.

Frequently asked questions

What is the main difference between CSS Grid and Flexbox?

Flexbox lays items out in one dimension, a row or a column. Grid lays items out in two dimensions, rows and columns at the same time. Flexbox works from the content out, while Grid works from the layout in.

Is CSS Grid better than Flexbox?

Neither is better overall. Grid is better when items must line up in both rows and columns, and Flexbox is better for a single row or column whose items size themselves. Most sites use both.

Can you use Grid and Flexbox together?

Yes. A grid item can be a flex container, and a flex item can be a grid container. A common pattern is a grid of cards where each card uses flexbox to arrange its own content.

Does the gap property work with Flexbox?

Yes. According to MDN, gap sets the gutters between rows and columns in flex, grid and multi-column containers, and it has been available across browsers since October 2017.

Should I use Grid for a whole page layout?

Usually, yes. Page regions such as a header, sidebar, main area and footer form a two-dimensional layout, which is what Grid is designed for. Flexbox is then a good fit for the contents of each region.

Related tools