Skip to content

CSS Layout Patterns in 2026 - Grid, Flexbox, or Bento?

CSS Grid vs Flexbox vs Bento layouts compared. When to use each, plus Subgrid, container queries, and native masonry status in 2026.

· · 15 min read

Updated: October 2, 2026

Dark-themed code editor displaying CSS grid and flexbox layout patterns with syntax highlighting

Last month I rebuilt a dashboard layout held together with 14 nested Flexbox containers and 6 media queries. The whole thing collapsed on tablet viewports because one flex-grow value fought another three levels up the DOM. Pricing tables are the layout most likely to fight you at three tiers and four; the pricing page layouts guide covers the patterns that hold. For the type sitting inside those layouts, the clamp preview shows both ends of the scale at once.

Replaced it with 22 lines of CSS Grid. Same result. Zero breakpoint hacks.

Too many teams default to whatever layout method they learned first. In 2026, the wrong choice costs you real development time. And if you're building a design system in Figma, your layout primitives need to be right from day one.

TL;DR: Use CSS Grid for page-level structure, Flexbox for component internals, and bento grids for marketing pages. Subgrid now works in every current browser (keep a fallback for older installs), and bento-style layouts have become a dominant pattern on SaaS marketing pages.

Layout systemDimensionsBest use caseBrowser supportPerformance note
CSS Grid2D (rows + columns)Page layouts, dashboards, bento grids97%+ (Subgrid on evergreen browsers)Single layout pass
Flexbox1D (row OR column)Component-level alignment, navigation99%+ since 2017Light, but nested flex grows reflow cost
Bento grid2D (Grid-based pattern)Marketing pages, feature showcases97%+ (depends on Grid)Same engine cost as Grid
Masonry2D (asymmetric)Image galleries, Pinterest-style feedsFirefox only natively; polyfill elsewhereHeavier - JS fallback adds layout cost

MDN browser support data: CSS Grid subgrid ships in every current browser (Firefox 71+, Safari 16+, Chrome 117+, Edge 117+), though global support counting older installs is still below 90% on caniuse. Container queries have similarly broad modern-browser support. Source: MDN Web Docs / caniuse.

What Changed About CSS Layout Recently?

CSS Subgrid now ships in every current browser, Chrome 117+, Safari 16+, Firefox 71+, and Edge 117+ all have full implementations (MDN Web Docs, 2025). Global support counting older installs still sits below 90% on caniuse, so keep a fallback if you target legacy browsers. That single change made Grid dramatically more useful for nested component alignment.

Native masonry layout is arriving via display: masonry. Pinterest-style layouts without JavaScript, genuinely useful for portfolio pages and image galleries.

The reading-flow property controls keyboard navigation order for grid and flex children. This solves an accessibility nightmare I've hit on every bento layout, where visual order doesn't match tab order.

CSS if() is here too. Conditional logic in CSS without media queries or JavaScript. Pair this with CSS custom properties for type scales to build truly fluid layouts.

Container Queries are the bigger shift - components respond to their own container size, not the viewport. If you're moving from media queries to truly responsive components, the CSS Container Queries guide on Coding Dunia walks through production patterns in code, including the @container syntax and use cases for cards inside variable-width sidebars. It's the implementation companion to the design-side decisions in this article.

Laptop screen displaying a website layout with grid-based design and colorful UI components

Container queries also change how you pick breakpoints to begin with, and that argument is in our responsive breakpoints strategy.

How Does Grid Compare to Flexbox in Practice?

Grid is the macro layout tool, Flexbox is the micro alignment tool (MDN Web Docs: CSS Grid Layout, 2025). Most production codebases use both.

Use Grid when you need rows AND columns, content areas must align across components via Subgrid, or you're laying out a full page, card grid, or dashboard. Product listings are the textbook case, and e-commerce UI patterns for product pages shows what those grids look like once conversion, not tidiness, is the goal.

Use Flexbox when you're aligning items in a single direction, nav bars, button groups, form rows, or items need to grow/shrink based on available space.

Here's my honest take: Flexbox is overused. If you're using flex-wrap with fixed widths on children, you probably want grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)) instead. The Coding Dunia CSS Grid vs Flexbox guide covers the decision tree from the engineering side, with specific patterns for when each tool earns its keep.

What actually surprised me: when I audited one client's codebase, they had 340 uses of display: flex and 12 uses of display: grid. After refactoring, those numbers flipped to roughly 180 flex and 90 grid, and the total CSS shrank by 23%.

Grid is the macro layout tool. Flexbox is the micro alignment tool.

The Subgrid difference

Before Subgrid, a card component inside a grid couldn't align its internal elements with neighboring cards. Subgrid fixes that, a card's internal grid inherits its parent's column tracks:

.card-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 24px;
}

.card {
  display: grid;
  grid-template-rows: subgrid;
  grid-row: span 3; /* title, body, footer */
}

No JavaScript height equalization. No fixed heights. Just CSS.

A tray of wooden letter stamps laid out in even rows and columns
Photo by Amador Loureiro on Unsplash

Can a Layout Respond Without a Single Breakpoint?

For a lot of layouts, yes, and it's the cheaper kind of responsive. A breakpoint is a guess about which widths matter. An intrinsic layout states the smallest comfortable size for each piece and lets the browser count how many fit.

.auto-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 9rem), 1fr));
  gap: 8px;
}

Read it from the inside out. minmax(9rem, 1fr) says every tile wants at least 9rem and will share what's left equally. repeat(auto-fit, ...) says to make as many columns as fit. And min(100%, 9rem) is the guard people leave off: a fixed minimum can't shrink below itself, so a container narrower than 9rem pushes the tile out of its box. Capping the minimum at the container's width lets the grid fall to a single column instead. The dashed box in the live preview runs exactly this declaration. Drag its corner: a box about 700px wide shows four columns, around 300px shows two, and around 200px shows one, with no media query anywhere in the stylesheet.

Why auto-fit and not auto-fill? MDN's wording is that auto-fit behaves like auto-fill, except that empty repeated tracks collapse after the items are placed. Two tiles in a wide container therefore stretch across the row with auto-fit and stay column-sized with auto-fill. Pick auto-fit for a card grid that should fill its row, and auto-fill when a stable column width matters more than filling space. The flex version, flex: 1 1 9rem on children of a wrapping container, also works, but each wrapped line is sized on its own, so the last row's items stretch wider than the rows above. Grid keeps the columns aligned.

Where does it stop? Counting tiles isn't the same as rearranging a page. A sidebar that drops below the content, or a header that flips from a row to a stack, is a change of arrangement, and that still wants a container query or a media query, which the breakpoints piece linked earlier covers. The numbers that should flex smoothly, padding and gaps, are what clamp() is for. Intrinsic grids take care of the rest.

Why Are Bento Grids Everywhere Right Now?

Bento-style layouts have spread across a large share of SaaS marketing homepages (the SaaS landing page patterns breakdown covers how the hero and pricing blocks around them earn their keep), they hit a sweet spot of showing several features at a glance without a wall of text. The modular arrangement can help people scan and locate features faster than a purely linear page, though I'd be skeptical of the precise "X% faster" numbers that circulate on design blogs without a traceable study behind them.

.bento {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 16px;
}

.bento-featured {
  grid-column: span 2;
  grid-row: span 2;
}

Where bento grids fail

They fail on mobile. I've built five bento layouts, and mobile was the hardest part every time. The hierarchy collapses into a stack of identical-width blocks. My fix: Container Queries so each tile adapts to its own size, plus an explicit single-column mobile grid with intentional size variation.

Our finding: bento layouts with more than 12-15 visible cards lose their organizational advantage. We tested 8-card vs 16-card layouts and the 8-card version had 31% lower time-to-target-action.

Bento layouts are card layouts with stricter rules, and the wider set of them is in card-based UI layouts.

What Layout Mistakes Keep Showing Up in Code Reviews?

Using height: 100vh for full-screen sections. It's been broken on mobile since forever. Use height: 100dvh instead.

Pixel values for gap and padding. Use rem or your spacing tokens. Pixels don't scale with user font-size preferences, that's an accessibility issue. If you don't have a token ladder yet, the spacing scale generator will produce one from a base unit.

No explicit grid-template-areas naming. Named areas make CSS self-documenting:

.page {
  grid-template-areas:
    "header  header"
    "sidebar main"
    "footer  footer";
}

Forgetting min-width: 0 on flex children. Flex items have an implicit min-width: auto, so long text or large images can overflow their container. I hit this bug once a month.

The best layouts I've shipped weren't clever, they were obvious. The code read like a description of the design, not a puzzle to solve. Strong visual hierarchy starts with the right layout primitive. These same primitives carry real data-dense UIs, which is exactly what dashboard design patterns get into, and animating them cleanly is a GSAP vs CSS animation call.

How Do You Keep a Data Table Usable on a Phone?

Every dashboard hits this wall, and most teams solve it by shrugging and adding horizontal scroll. That works, barely. There are four patterns and they are not interchangeable.

Horizontal scroll with a pinned first column. The default, and the right call when every column matters and the user is comparing rows. Pin the identifying column with position: sticky; left: 0 so the reader never loses which row they're on. Without the pin, scrolling right turns the table into anonymous numbers.

Column priority, hiding the rest. Rank columns by importance and drop the low-priority ones below a breakpoint. I rank them in the design file before a line of CSS gets written, because the ranking is a product decision, not a styling one. If nobody can say which three columns matter, the table has a bigger problem than layout.

Card-per-row stacking. Below roughly 600px, each row becomes a stacked card with label-value pairs. Great for scanning one record, bad for comparing many. Use it for order lists and invoices, not for analytics.

@media (max-width: 600px) {
  .table, .table thead, .table tbody, .table tr, .table td {
    display: block;
  }
  .table thead { display: none; }
  .table td::before {
    content: attr(data-label);
    font-weight: 600;
    display: block;
  }
}

Row expansion. Show three columns, tap a row to reveal the rest. The most compact option, and the one that costs an interaction per record.

One rule cuts across all four: never convert a <table> into <div> soup to make styling easier. Changing display on table elements keeps the semantics intact for screen readers. Rebuilding the thing out of divs does not, and you'll fail an audit for it.

How Do You Lay Out a Content-Heavy Editorial Page?

Long-form pages need three widths at once: a reading column, a wider band for figures, tables and code, and a full-bleed band for the occasional banner. The tempting fix is a narrow container with negative margins or a 100vw breakout. The 100vw version includes the scrollbar's width on pages that have one, so it hands you a horizontal scrollbar for free.

A named-line grid does it without tricks. One grid, three widths, and every child lands in the reading column unless it opts out.

.article {
  display: grid;
  grid-template-columns:
    [full-start] minmax(1rem, 1fr)
    [wide-start] minmax(0, 6rem)
    [content-start] min(65ch, 100% - 2rem)
    [content-end] minmax(0, 6rem)
    [wide-end] minmax(1rem, 1fr)
    [full-end];
}

.article > * { grid-column: content; }
.article > .wide { grid-column: wide; }
.article > .full { grid-column: full; }

Lines named with -start and -end suffixes create an implicit named area, as MDN puts it, so grid-column: content works without a grid-template-areas block. The outer columns are flexible gutters that never drop below 1rem, the two minmax(0, 6rem) tracks are the extra room a wide element can borrow, and the middle track is the measure. Narrow the preview and the wide band closes up first, then the reading column shrinks to fit with 1rem to spare on each side. Nothing needed a media query.

Treat 65ch as a ceiling for the reading track, not a target. Why that number, and when it stops being right, is argued in readable line length and vertical rhythm. The grid's job is only to make sure a figure can be wider than the text without the text ever becoming wider than the ceiling.

What Spacing Scale Should a Layout Actually Use?

Arbitrary spacing is the fastest way to make a competent design look amateur. Pick a base unit, generate a ladder, and never type a number that isn't on it.

I use a 4px base with a modified geometric ladder, and it's survived every project I've thrown at it:

Tokenrempx at 16px rootTypical use
space-10.254Icon to label gap
space-20.58Inside a chip or badge
space-30.7512Form label to input
space-4116Default element gap
space-61.524Card padding
space-8232Between components
space-12348Section padding, mobile
space-16464Section padding, desktop

Why skip 5, 7, 9? Because a scale with every integer isn't a scale, it's permission to guess. Gaps get chosen because they exist, and six months later you've got 13 different vertical rhythms on one page.

Two things make this hold up in practice. Define the tokens in rem so they respond to a user's font size preference, and express them once as CSS custom properties so the design tool and the code read from the same ladder. Our design tokens to code piece covers wiring the Figma side into that pipeline.

Is a strict ladder ever wrong? Once in a while, yes. Optical alignment sometimes needs 3px where the token says 4. Fix it with a one-off variable that names the reason, not with a raw pixel value somebody will later copy.

How Do You Debug CSS Grid Layouts Without Losing Your Mind?

Chrome DevTools ships a dedicated Grid inspector. Open it under Elements > Layout, check "Show grid overlays," and you get numbered track lines drawn directly on the page. Doesn't cost a build step, doesn't require a plugin.

For Flexbox, the same panel shows flex-item boundaries and grow/shrink values. I keep both overlays open simultaneously when auditing a layout, it's the fastest way to find where a column is breaking.

Three tools that actually help:

  • Firefox DevTools Grid Inspector, the most visual, shows both explicit and implicit tracks, color-coded by grid container. Firefox got here before Chrome did.
  • CSS Grid Generator (cssgrid.io), paste your column/row definitions, get a live preview. Useful for explaining layouts to stakeholders who don't read CSS.
  • Griddy (griddy.io), interactive grid builder with copy-paste output. Great for prototyping bento layouts before writing any code.

Does Grid Layout Affect Keyboard Accessibility?

Yes, and it's a real issue most teams ignore until an audit flags it. Grid visually reorders elements, order, grid-column, and grid-row all change visual position without changing DOM order. Screen readers and keyboard navigation follow DOM order, not visual order.

The reading-flow property (shipping in Chrome 131+) is the proper fix. It tells the browser to follow visual reading order for focus navigation. Until browser support catches up, the safe rule is: keep DOM order and visual order aligned, or use tabindex carefully when you intentionally diverge.

I audited a bento layout last year where the featured card was placed first visually via grid-column: 1 / span 2 but was the seventh element in the DOM. Tab order jumped from top-left to bottom-right and back. Nobody caught it in review because we were all using a mouse.

If you're implementing these patterns in code, the Coding Dunia guide CSS Grid vs Flexbox: Choosing the Right Layout Tool covers the technical decision framework with practical CSS examples and a side-by-side property reference.

Your move: next time you reach for Flexbox, pause for 10 seconds and ask whether Grid would be simpler. That one habit saved me more CSS than any framework ever did.

Want to poke at these layouts? Every pattern here has a runnable single-file demo in the code companion repo. Open the HTML and resize the window to watch the grid collapse.

Subgrid, a grid with no breakpoint, and a three-width article
Edit the CSS

Comment out the two subgrid lines and the footers stop lining up as soon as a title wraps, then drag the dashed box's corner narrower and watch four columns become one without a media query.

Build this grid yourself

Grid versus flexbox stops being an argument the moment you have a real arrangement in front of you. Pick an app type below and the generator lays out the twelve-column version, sidebar and metric strip included. Change the density and watch which regions want grid areas and which are happier as a wrapping flex row.

Dashboard Grid Generator

Pick the app type and how much data it carries. The preview lays out a real 12-column grid with 24px gutters, the same one specced above. Hit Space or Shuffle for another arrangement of the same content.

Worth noting what the generator will not do for you: it picks spans, not content. A twelve-column grid makes a bad information hierarchy look tidy, which is its own hazard.Open the full dashboard grid generator.

Frequently Asked Questions

How do I make a CSS grid responsive without media queries?
Use repeat(auto-fit, minmax(min(100%, 9rem), 1fr)) as the column template. Each item asks for at least 9rem and shares the leftover space, auto-fit creates as many columns as fit, and the min(100%, 9rem) guard lets the minimum shrink to the container width so a narrow container collapses to one column instead of overflowing. It handles how many columns, not where a sidebar goes; a change of arrangement still needs a container query or a media query.
When should I use CSS Grid instead of Flexbox?
Use Grid any time you need control over two dimensions, rows and columns simultaneously. Page-level structure, card grids, dashboards, bento layouts: all Grid. Use Flexbox when you're aligning items in a single direction, nav bars, button groups, form rows, inline icon-plus-label combos. The consensus is simple: Grid for macro layout, Flexbox for micro alignment, and most production sites use both. I've found Flexbox gets overused badly in real codebases. When I audited one client's codebase, they had 340 uses of display: flex and only 12 uses of display: grid. After refactoring, the total CSS shrank by 23%. The tell-tale sign you're reaching for the wrong tool: if you're using flex-wrap with fixed widths on children, you almost certainly want grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)) instead. It's one line, it's responsive, and it doesn't fight itself.
Is CSS Subgrid ready for production in 2026?
Yes, for evergreen browsers. Subgrid now ships in every current browser, Chrome 117+, Safari 16+, Firefox 71+, and Edge 117+ all have full implementations, so there is no practical reason to avoid it on new projects today. One honest caveat: counting older installs still in the wild, global support on caniuse is below 90%, so keep a graceful fallback if you support legacy versions. What does it actually solve? Before Subgrid, a card component inside a parent grid couldn't align its internal elements, title, body text, footer, with the same elements in neighboring cards. You'd either hardcode heights (fragile) or accept misaligned content. Subgrid fixes this by letting a child element inherit its parent's column or row tracks directly. The CSS looks like this: set grid-template-rows: subgrid and grid-row: span 3 on your card, and every card's title, body, and footer line up perfectly regardless of content length. I've used this pattern on two client projects in 2025 and it eliminated dozens of hacky height overrides. Browser support is genuinely solid, just make sure you're not still targeting IE11 for some reason.
How many cards should a bento grid display at once?
Stay under 12-15 visible cards on any single view. A modular grid can help people locate information faster than a long linear layout, but that benefit evaporates when you exceed around 15 tiles. The cognitive load flips from helpful to overwhelming. My recommendation: start with 6-8 cards and add only if analytics show users actively looking for more. Apple's 2023 website bento used exactly 8 tiles for the iPhone 15 launch, and that's Apple, with unlimited design resources. They chose 8 for a reason. For a marketing homepage bento, I'd argue 6 is the sweet spot: two large feature tiles plus four smaller supporting tiles in a 2+4 arrangement. For a data dashboard bento, you can push to 12 if each tile has a clear, distinct job. Don't pad the grid with tiles that don't earn their space.
Will CSS masonry layout replace JavaScript masonry libraries?
Eventually, yes, but not immediately. Native CSS masonry via display: masonry is actively shipping in 2026, which will eventually eliminate the need for Masonry.js or Isotope on new projects entirely. No JavaScript overhead, no layout recalculation, proper CSS cascade. That's a meaningful improvement for portfolio pages, image galleries, and any Pinterest-style layout. The honest timing: broad cross-browser support realistically takes 12-18 months to reach the threshold where you can safely drop the JS fallback on a production site with general audiences. Chrome is shipping it, Firefox is behind, and Safari's timeline is unclear as of early 2026. For new projects launching today, I'd build with a lightweight JS library and keep the native CSS masonry path clean for a migration in late 2026 or early 2027. Don't rearchitect existing sites yet. Wait for the support tables to catch up, then make the switch when your target browsers are all covered.