Back to CSS
CSS
medium
mid

Would you use Flexbox or CSS Grid for an e commerce product layout with three columns?

CSS Grid. Product grids are inherently 2D (rows AND columns of equal-sized cards), and Grid handles that natively with one rule: 'grid-template-columns: repeat(auto-fill, minmax(240px, 1fr))'. It gives equal column widths, fluid responsiveness without media queries, and aligned rows automatically. Flexbox is 1D — to fake a grid you fight wrap behavior, leftover-item alignment, and equal heights. Use Flexbox inside each card; Grid for the layout.

5 min read·~5 min to think through

Short answer: CSS Grid. Product listings are a textbook 2D layout — rows and columns of equal-sized cards — and that's exactly what Grid was designed for.

The Grid solution

css
.products {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 16px;
}

That's the whole layout. Three things it gives you for free:

  1. Equal column widths. Every card is the same width; cards never stretch unevenly because of content differences.
  2. Auto-responsive. auto-fill + minmax packs as many 240px+ columns as fit, then flexes them to fill the row. No media queries needed for "3 cols on desktop, 2 on tablet, 1 on mobile."
  3. Aligned rows. Items in the same row share a height — no jagged baselines when one card has a longer title.

Why Flexbox is the worse choice here

Flexbox is 1D. To force a grid out of it you write:

css
.products { display: flex; flex-wrap: wrap; gap: 16px; }
.products > * { flex: 0 0 calc(33.333% - 11px); }

Now the problems:

  • Leftover-item alignment. 10 items in a 3-col layout = 1 orphan on the last row, stretched or left-aligned awkwardly. Grid keeps it the same width as the others.
  • Different per-breakpoint math. Every breakpoint needs a new flex-basis calc. Grid's auto-fill covers all sizes in one rule.
  • Cross-row alignment is impossible. If row 1 has a tall card, row 2 cards don't align to row 1's tracks. Grid does.
  • Gap math leaks into widths. calc(33.333% - 11px) is a fragile hack that breaks if you change the gap.

The right division of labor

Grid for the page layout, Flexbox for the card internals:

css
.product-card {
  display: flex;
  flex-direction: column;
}
.product-card .footer { margin-top: auto; } /* pin price + button to bottom */

This is the canonical pattern: Grid for 2D macro layout, Flex for 1D micro alignment inside each cell.

When Flexbox actually wins

  • A nav bar (1D, items have varying widths).
  • A toolbar with a "push the last item right" requirement (margin-left: auto).
  • Anywhere items are inherently different sizes and should pack naturally.

A product grid is none of these.

Follow-up questions

  • How would you handle a 'featured' product that spans 2 columns?
  • How do you ensure all cards have equal heights when content varies?
  • What's the difference between auto-fill and auto-fit?
  • How would you add a sidebar with filters next to the grid?

Common mistakes

  • Using percentage widths with flex and forgetting to subtract gap — breaks when gap or column count changes.
  • Using auto-fit instead of auto-fill — auto-fit collapses empty tracks, so 1 item stretches across the full width.
  • Setting fixed heights on cards instead of letting Grid equalize them.
  • Using media queries to swap column counts when minmax() + auto-fill would do it implicitly.
  • Putting display:flex on the grid container itself, then complaining Grid 'doesn't work.'

Performance considerations

  • Both layout engines are highly optimized in modern browsers; the perf delta is negligible for typical product grids (<500 items). For very large lists (1000+), neither matters — you need virtualization (react-window) and Grid still wins because windowed rows compute item geometry trivially.

Edge cases

  • Last-row orphans: Grid keeps them the same width as siblings; Flex stretches or left-aligns them.
  • Variable card heights — Grid aligns by row, Flex doesn't.
  • Very narrow viewports — minmax(240px, 1fr) on a 320px screen still gives 1 column, no overflow.
  • Mixed-span items (a hero card spanning 2 cols) — trivial in Grid via grid-column: span 2; awkward in Flex.

Real-world examples

  • Amazon, Shopify, and most e-commerce product listings use Grid for the product matrix.
  • Pinterest's masonry layout is the rare case where you need CSS columns or a JS masonry library — neither Grid nor Flex handles uneven heights well.
  • Image galleries (Unsplash, Google Photos) — Grid with auto-fill is the standard.

Senior engineer discussion

The right answer for a senior interview is not just 'Grid' — it's articulating the 2D vs 1D distinction, then noting that real product cards use both: Grid for the page-level layout, Flex inside each card. Also worth mentioning: container queries (@container) now let cards adapt to their own width regardless of viewport, which pairs naturally with Grid.