Articles

CSS Grid vs. Flexbox: When to Use Each

Grid and Flexbox aren't rivals — they solve different problems. A simple rule of thumb, with examples, for choosing the right layout tool every time.

Takina Takina · · Updated · 4 min read
A stylized browser window and layout

Flexbox lays out items along a single axis — a row or a column. CSS Grid lays out items in two dimensions — rows and columns at the same time. That one-line rule settles the “which should I use” question in almost every case: arranging things along one axis is a Flexbox job; building a layout where rows and columns must stay aligned is a Grid job.

Both are display values you set on a container element in the DOM, and both exist to replace the float and table hacks that dominated CSS layout for its first two decades. They aren’t rivals. Modern pages use both, usually nested inside each other.

How Flexbox thinks: one axis

display: flex gives the container a main axis (horizontal by default, vertical with flex-direction: column) and a cross axis perpendicular to it. Every alignment decision maps onto those two axes: justify-content distributes items along the main axis, align-items aligns them on the cross axis.

The other defining trait is that Flexbox sizes from the content out. Items start at their natural size, then flex-grow and flex-shrink negotiate over the leftover space. That is why Flexbox feels effortless for toolbars, nav bars, and button groups — the content decides, the container adapts.

The classic nav bar:

.nav {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
}

Logo on the left, links on the right, everything vertically centered — three declarations.

Centering one element in both directions, the historically painful problem, is just as short:

.hero {
  display: flex;
  justify-content: center;
  align-items: center;
}

Grid’s place-items: center does the same in one line — centering is one case where either tool is fine.

How Grid thinks: tracks first

display: grid works from the container in. You define the structure — column and row tracks — before any item is placed, and children then occupy cells in that structure. The fr unit shares out remaining space proportionally, and items can be placed automatically, by line number, or by named area.

The workhorse pattern is a responsive card gallery with no media queries:

.gallery {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 1.5rem;
}

auto-fill creates as many columns as fit; minmax(240px, 1fr) keeps each at least 240px wide and stretches them equally. Cards reflow from four columns to one as the container narrows — and every row stays aligned, because tracks are shared across the whole grid.

Grid is also the right tool for the full page skeleton:

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

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

The grid-template-areas block is an ASCII picture of the page. Rearranging the layout at a breakpoint means redrawing that picture inside a media query — no markup changes at all.

Which one should you reach for?

SituationUse
Nav bar, toolbar, button row, tag listFlexbox
Items should size to their content and share leftover spaceFlexbox
Card gallery that reflows with available widthGrid (auto-fill + minmax)
Rows and columns must stay alignedGrid
Whole-page structure (header, sidebar, main, footer)Grid
Form labels and inputs aligned across rowsGrid
Centering a single elementEither

Common mistakes

  • Using Grid for a simple row. Writing grid-template-columns: auto auto just to put an icon next to a label defines structure you don’t need. Flexbox handles one-axis jobs with less code and better content-driven sizing.
  • Nesting flex containers to fake a grid. Wrapped flex rows lay out independently — each line distributes space on its own, so nothing lines up vertically across rows. If you’re adding fixed widths and wrapper divs to force columns into alignment, that’s the signal you wanted Grid all along.
  • Margins as gutters. gap works in both Grid and Flexbox in every modern browser. It spaces items without first-child/last-child margin hacks and never double-counts at the edges.
  • Fighting the sizing model. Flexbox is content-out; Grid is container-in. Forcing rigid column widths onto flex items, or forcing Grid cells to hug content on both axes, usually means the other tool fit better.

Subgrid: aligning nested content

Grid had one long-standing gap: a nested grid couldn’t see its parent’s tracks, so card internals — title, body, footer — wouldn’t align across cards with different amounts of text. subgrid fixes that, and it has shipped in all major browsers:

.card {
  grid-row: span 3;
  display: grid;
  grid-template-rows: subgrid; /* inherit the parent's row tracks */
}

Each card spans three parent rows and lets its children align to them, so every card footer sits on the same line no matter how long each card’s text runs.

Where this fits in your stack

Utility frameworks don’t change the decision. Tailwind CSS exposes both models as classes — flex justify-between versus grid grid-cols-3 — so you still need to know which model you’re driving. And once cards live in grid tracks, container queries let each card respond to its track’s width instead of the viewport, which pairs naturally with auto-fill galleries.

The takeaway

Flexbox distributes items along one axis and sizes from the content out; Grid defines two-dimensional tracks and places items into them. Reach for Flexbox for rows, columns, and anything content-driven; reach for Grid for card galleries, aligned forms, and the page skeleton — and compose them freely, Grid outside, Flexbox inside. gap works in both, and subgrid covers the last hard case of aligning nested content. When rows and columns must line up, it’s Grid; otherwise Flexbox is usually less code.

Takina Takina · · 4 min read

CSS object-fit and object-position, Explained

object-fit controls how an image or video is cropped inside its box, and object-position controls which part of it stays visible. How they work together.

#CSS #Web Development #Frontend
Takina Takina · · 5 min read

CSS inherit, initial, unset & revert Explained

CSS's four global keywords control where a property's value comes from. How inherit, initial, unset, and revert differ, with a comparison table.

#CSS #Web Development #Frontend
Takina Takina · · 4 min read

Dynamic Viewport Units: dvh, svh, and lvh Explained

dvh, svh, and lvh fix the classic mobile vh bug where browser toolbars cut off full-height layouts. Here's what each unit measures and when to use it.

#CSS #Web Development #Frontend