What is the difference between CSS Grid and Flexbox, and when would you choose one over the other?

Beginner10 min interview
Skills tested:
Describing Grid as two-dimensional and Flexbox as one-dimensionalExplaining container-driven versus content-driven sizingChoosing the right model for a page shell, a toolbar, and a card galleryKnowing which alignment properties exist in each modelRecognising when nesting the two is the correct answer

Advertisement

🧩 Scenario

This is the layout decision you make dozens of times in a single application, usually without articulating it. A page shell with a header, sidebar, content, and footer is a Grid problem because the structure is known and two-dimensional. A toolbar whose buttons size to their labels is a Flexbox problem because the content drives the sizing. Getting this right the first time avoids the percentage-and-negative-margin workarounds that define layouts built with the wrong tool.

Architecture Walkthrough

One Dimension Versus Two

Flexbox is a one-dimensional layout model. It lays items out along a single axis and controls their distribution and alignment on that axis, with the cross axis handled only as alignment within a line. When items wrap, each line is sized independently, so there is no relationship between an item in the first line and an item in the second.

Grid is a two-dimensional model. It defines rows and columns simultaneously, and every item is placed into that structure. Items in different rows share column tracks, so a wide item in row three widens that column for every row. That column-and-row relationship is the thing Flexbox structurally cannot express.

This is why a wrapped flex row does not produce a grid. The items in each line size independently, so the third item in line one and the third item in line two have no reason to share a width. In Grid they do, because they occupy the same track.

Content-Driven Versus Container-Driven

The more useful framing for day-to-day decisions is who decides the sizes.

Flexbox is content-driven. Items are sized from their content by default and then grow or shrink from there. You describe how space should be distributed and let the content determine the starting point. This is exactly right for a toolbar of buttons with different label lengths, a navbar, a row of tags, or a form row where each field should take the space it needs.

Grid is container-driven. The container declares the track structure up front, and items are placed into it. The tracks exist whether or not anything occupies them. This is exactly right for a page shell, a dashboard, a calendar, a data table layout, or any design where the structure is known in advance and should not depend on content length.

Feature Differences That Matter

Beyond the model, some capabilities exist in only one.

Grid has grid-template-areas, which lets you name regions and draw the layout as ASCII art, and it can rearrange those areas at a breakpoint by rewriting one property. It has explicit line-based placement, so an item can be told to span from column 2 to column 5. It supports minmax(), fr units, auto-fit, auto-fill, and repeat(), which together make responsive track sizing possible without media queries. It also supports deliberate overlap by placing two items in the same cell, with z-index working on grid items without any positioning.

Flexbox has flex-grow, flex-shrink, and flex-basis, giving per-item control over how each one responds to available space, which Grid has no direct equivalent for. It also has content-based wrapping that needs no track definition at all.

On alignment, Grid has the full set: justify-items, justify-self, align-items, align-self, justify-content, align-content. Flexbox has no justify-items or justify-self, which is why pushing a single flex item to the far end of the main axis is done with an auto margin rather than a self-alignment property.

The Decision Rule

Ask two questions. Does the layout need to control both rows and columns as a related structure? If yes, Grid. Does the layout distribute space along one axis where content should determine the natural sizes? If yes, Flexbox.

In practice most real pages use both, nested. A Grid defines the page shell or the card gallery, and inside each area a Flexbox row handles a header with a title on the left and actions on the right. That composition is not a compromise; it is each model doing the job it was designed for.


Key Code Explained

/* GRID: the structure is known and two-dimensional */
.page-shell {
  display: grid;
  grid-template-columns: 240px 1fr;
  grid-template-rows: auto 1fr auto;
  grid-template-areas:
    'header  header'
    'sidebar main'
    'footer  footer';
  min-height: 100dvh;
}
/* Rearranging the whole layout at a breakpoint is one property */
@media (max-width: 768px) {
  .page-shell {
    grid-template-columns: 1fr;
    grid-template-areas:
      'header'
      'main'
      'sidebar'
      'footer';
  }
}

/* FLEXBOX: content-driven distribution along one axis */
.toolbar {
  display: flex;
  align-items: center;
  gap: 8px;
}
.toolbar .spacer {
  margin-inline-start: auto; /* no justify-self in Flexbox */
}
/* Buttons size to their labels; no track definition needed */

/* Grid does what wrapped Flexbox cannot: shared tracks across rows */
.gallery {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 16px;
}
/* Every card in column 3 shares a width, across every row */

/* The Flexbox imitation of a grid — items in different lines
   size independently, so the columns do not line up under
   varying content, and the last row stretches oddly */
.fake-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
}
.fake-grid > * {
  flex: 1 1 240px; /* lines size independently */
}

/* THE REAL ANSWER: nest them */
.dashboard {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: 24px;
}
.dashboard .card-header {
  display: flex;             /* one axis, content-driven */
  justify-content: space-between;
  align-items: center;
}

The .gallery and .fake-grid pair is the clearest demonstration of the dimensional difference. Both produce a wrapping set of cards, and at first glance they look equivalent. The difference appears when card content varies: in the Grid version every card in a given column shares a width because they share a track, while in the Flexbox version each line resizes independently and the columns drift out of alignment. The Flexbox version also stretches the final row's items to fill the width, which is usually not the intent.

The .page-shell media query shows Grid's other distinctive capability. Reordering a four-region layout is one property rewrite with grid-template-areas, with no changes to the markup, no order values on children, and no source-order versus visual-order accessibility problem to reason about.


Tradeoffs

AspectFlexboxGrid
DimensionsOne axisRows and columns together
Sizing driven byContentContainer's track definition
Per-item space controlflex-grow / shrink / basisNo direct equivalent
Named regionsNogrid-template-areas
Track sizing helpersNofr, minmax(), auto-fit, repeat()
justify-self / justify-itemsNot availableAvailable
Deliberate overlapAwkwardNatural, same cell + z-index
Best forToolbars, navbars, tag rows, form rowsPage shells, dashboards, galleries, calendars

What Interviewers Actually Check

  • Whether you lead with the dimensional difference rather than with "Grid is newer"
  • Whether you can frame it as content-driven versus container-driven sizing
  • Whether you can pick correctly for concrete layouts and justify the choice
  • Whether you know a capability that exists in one model and not the other
  • Whether you recognise that nesting both is the normal answer for a real page

Follow-Up Questions

  1. Why does justify-self not exist in Flexbox, and what is the idiomatic workaround?
  2. How does place-content differ between a Grid container and a Flex container?
  3. When would grid-auto-flow: dense be useful, and what accessibility concern does it raise?
  4. Can you achieve a masonry layout with either model today, and what does the CSS masonry proposal add?
  5. How do subgrid and display: contents help when a nested component needs to align to its grandparent's tracks?

Common Candidate Mistakes

  • Framing the answer as Grid being the modern replacement for Flexbox, which misses that they solve structurally different problems
  • Building a card gallery with wrapped Flexbox and percentage widths, then fighting the independent line sizing and the stretched final row that Grid tracks would have handled
  • Using Grid for a toolbar or navbar where the whole point is that buttons size to their labels, adding track definitions that constrain content unnecessarily
  • Reaching for justify-self on a flex item, which does not exist, instead of using an auto margin
  • Treating the choice as exclusive, when a Grid shell containing Flexbox rows is the standard composition in production layouts

Interview Readiness Checklist

Before you leave this question, make sure you can answer:

  • Can you state the dimensional difference in one sentence?
  • Can you explain content-driven versus container-driven sizing with a concrete example of each?
  • Can you pick the right model for a page shell, a toolbar, a card gallery, and a form row, and justify each?
  • Can you name an alignment property that exists in Grid but not Flexbox, and explain the workaround?
  • Can you describe a real layout that nests both, and say which model handles which part?

Summary

Flexbox is a one-dimensional model: it distributes and aligns items along a single axis, and when items wrap, each line sizes independently with no relationship between lines. Grid is two-dimensional: it defines rows and columns as one structure, and items placed into it share tracks, so a column's width is common to every row. That shared-track relationship is what wrapped Flexbox structurally cannot reproduce.

The practical framing is who controls sizing. Flexbox is content-driven, sizing items from their content and then growing or shrinking them, which suits toolbars, navbars, tag rows, and form rows. Grid is container-driven, declaring tracks up front regardless of content, which suits page shells, dashboards, galleries, and calendars. Grid also brings capabilities with no Flexbox equivalent, including grid-template-areas, line-based placement, fr units, minmax(), auto-fit, and the full set of self-alignment properties. Flexbox in turn offers per-item flex-grow, flex-shrink, and flex-basis control that Grid has no direct counterpart for.

Choose Grid when the layout needs both rows and columns as a related structure, and Flexbox when a single axis distributes space around content-determined sizes. Most real pages use both: a Grid shell or gallery with Flexbox rows inside each region, which is each model doing exactly what it was designed for rather than a compromise between them.

Frequently Asked Questions

Can you nest one inside the other?

Yes, and you usually should. A grid page shell with flex rows inside its areas is the most common real-world composition, and a grid item can itself be a flex container with no restrictions.

Is Grid a replacement for Flexbox?

No. They solve different problems. Grid places items into a structure the container defines; Flexbox distributes space among items along a single axis based on their content.

Advertisement


Stay Updated

Get the latest frontend challenges, interview questions and tutorials delivered to your inbox.

Advertisement