CSS Grid vs Flexbox: When to Use Which in 2026
“Should I use Grid or Flexbox?” is one of the most common questions I get from developers learning CSS layout. The standard answer—“Grid is for two-dimensional layouts, Flexbox is for one-dimensional”—is technically correct but practically unhelpful. Here’s what I actually tell people when they ask.
The Quick Decision Framework
Before diving into details, here’s the decision I make mentally for every layout task:
Use Flexbox when: Items flow in one direction and their sizes should adapt to content. Navigation bars, button groups, card footers, centering content, distributing space between items.
Use Grid when: You need items placed in specific positions on a two-dimensional grid. Page layouts, card grids, dashboard panels, form layouts, anything where alignment across both rows and columns matters.
Use both when: Complex components often benefit from Grid for the outer structure and Flexbox for inner component layouts.
That covers about 90% of decisions. The remaining 10% is where it gets interesting.
Where Flexbox Wins
Flexbox is better when content size should drive layout size. A navigation bar is the textbook example:
.nav {
display: flex;
gap: 1rem;
align-items: center;
}
.nav-item {
/* Each item sizes to its content */
}
.nav-spacer {
flex: 1; /* Pushes items apart */
}
Each nav item is as wide as its text. The spacer fills remaining space. If you add or remove items, the layout adjusts automatically. You don’t need to specify column widths or think about grid tracks.
Centering is another Flexbox strength:
.center-me {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
Yes, you can center with Grid (place-items: center), but Flexbox centering is more intuitive when you’re centering a single child element.
Button groups and inline form layouts are natural Flexbox territory:
.button-group {
display: flex;
gap: 0.5rem;
}
.button-group button {
/* Buttons size to content by default */
}
/* Or distribute evenly */
.button-group-even button {
flex: 1;
}
The pattern is consistent: one direction of flow, content-driven sizing, flexible distribution of space. That’s Flexbox’s domain.
Where Grid Wins
Grid is better when you want to define the layout structure independently of content. A card grid is the classic example:
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 1.5rem;
}
This creates a responsive grid where cards are at least 280px wide, expanding to fill available space, wrapping to new rows as needed. No media queries. The auto-fill and minmax combination handles responsiveness automatically.
Try doing this with Flexbox. You can approximate it with flex-wrap and percentage widths, but it’s messier and harder to control the gap and alignment behaviour consistently.
Page layouts are another Grid strength:
.page-layout {
display: grid;
grid-template-columns: 250px 1fr 300px;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"header header header"
"sidebar main aside"
"footer footer footer";
min-height: 100vh;
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.aside { grid-area: aside; }
.footer { grid-area: footer; }
Grid template areas let you describe the layout in a way that’s almost visual. You can see the structure by reading the CSS. Changing the layout for different screen sizes is just redefining the template areas in a media query.
Dashboard layouts benefit enormously from Grid’s placement capabilities:
.dashboard {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-template-rows: auto;
gap: 1rem;
}
.widget-large {
grid-column: span 2;
grid-row: span 2;
}
.widget-wide {
grid-column: span 2;
}
Widgets can span multiple cells without affecting other widgets’ positions. This kind of layout is painful with Flexbox.
The Overlap Zone
Some layouts work fine with either technology. Equal-width columns:
/* Flexbox approach */
.equal-columns-flex {
display: flex;
gap: 1rem;
}
.equal-columns-flex > * {
flex: 1;
}
/* Grid approach */
.equal-columns-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
}
Both work. I slightly prefer Grid here because grid-template-columns is more explicit about the number of columns, but Flexbox’s flex: 1 is perfectly fine.
The choice in the overlap zone often comes down to what else is happening in the layout. If the equal columns are part of a larger Grid layout, use Grid. If they’re inside a Flexbox container, use Flexbox. Consistency within a component is more important than choosing the “theoretically correct” tool.
Nesting Grid and Flexbox
The most effective approach for complex layouts is using both. Grid for the macro structure, Flexbox for the micro components:
/* Outer layout: Grid */
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 1.5rem;
}
/* Each card: Flexbox */
.card {
display: flex;
flex-direction: column;
}
.card-body {
flex: 1; /* Takes remaining space */
}
.card-footer {
display: flex;
justify-content: space-between;
align-items: center;
}
The Grid handles placing cards in a responsive grid. Flexbox handles the internal card layout—pushing the footer to the bottom and distributing items within it. Each tool does what it’s best at.
Subgrid: The Game Is Changing
CSS Subgrid, now supported in all major browsers as of 2024, changes the Grid vs Flexbox calculation. Subgrid lets nested grid items align to the parent grid’s tracks.
.card-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1.5rem;
}
.card {
display: grid;
grid-template-rows: subgrid;
grid-row: span 3; /* Header, body, footer */
}
This makes card headers, bodies, and footers align across cards in the same row—something that was impossible without JavaScript before subgrid. If you’re building card grids where consistent alignment matters, subgrid is a significant improvement.
Common Mistakes
Using Flexbox for everything. I see developers who learned Flexbox first and use it for page layouts, card grids, and complex two-dimensional arrangements. It works, sort of, but the CSS becomes brittle and full of workarounds.
Using Grid for everything. The opposite mistake. Grid for a simple centred button or a horizontal nav bar is overkill. It works but it’s more code than necessary.
Forgetting gap. Both Grid and Flexbox support the gap property now. Stop using margins for spacing between layout children. gap is cleaner, doesn’t need to be removed from first/last children, and works consistently.
Not testing with variable content. Your layout might look perfect with three equal cards. What happens with five? With one? With a card containing a very long title? Test with realistic content variations, not just ideal cases.
My Rule of Thumb
When I’m coding and need to decide quickly, I ask myself: “Am I arranging items in a line or on a grid?” If it’s a line—horizontal or vertical—I reach for Flexbox. If items need to align on both axes, I use Grid. If I’m not sure, I start with Flexbox (it’s slightly simpler) and switch to Grid if it gets awkward.
Both tools are mature, well-supported, and performant in 2026. There’s no wrong choice—just more or less appropriate ones for specific situations. Use what makes your layout code clearest and most maintainable. That’s what matters in the end.