CSS Flexbox vs Grid: When to Use Which (2026 Guide)
CSS Flexbox and CSS Grid are the two modern layout systems that have completely replaced the old days of floats, clearfixes, and table-based layouts. Both are powerful, both are well-supported across all browsers, and both solve real layout problems. But they are not interchangeable. Each one excels in different situations, and understanding when to reach for Flexbox versus Grid is one of the most practical CSS skills you can develop.
This guide covers everything you need to know: what each system does, how they differ, when to use one over the other, and how to combine them for complex real-world layouts. Whether you are building a navigation bar, a dashboard, a card grid, or a full page layout, you will know exactly which tool to reach for by the end of this article.
What Is CSS Flexbox?
Flexbox (Flexible Box Layout) is a one-dimensional layout system. It arranges items along a single axis, either horizontally (a row) or vertically (a column). You define a flex container, and the children become flex items that can grow, shrink, and distribute space along that one axis.
The "one-dimensional" part is the key concept. Flexbox is designed to handle layout in one direction at a time. You can control how items wrap to new lines, but each line operates independently. Flexbox does not give you precise control over both rows and columns simultaneously.
Here is a basic Flexbox setup:
.flex-container {
display: flex;
flex-direction: row; /* Items flow left to right */
justify-content: center; /* Center items along the main axis */
align-items: center; /* Center items along the cross axis */
gap: 1rem; /* Space between items */
}
And here is what it looks like conceptually:
Main axis (horizontal) ───────────────────────►
┌──────────────────────────────────────────┐
│ │ ▲
│ ┌──────┐ ┌──────┐ ┌──────┐ │ │
│ │Item 1│ │Item 2│ │Item 3│ │ │ Cross axis
│ └──────┘ └──────┘ └──────┘ │ │ (vertical)
│ │ │
└──────────────────────────────────────────┘ ▼
The main axis is the direction items flow (set by flex-direction). The cross axis is perpendicular to it. justify-content controls distribution along the main axis. align-items controls alignment along the cross axis.
Core Flexbox Properties
On the container:
display: flex— creates the flex formatting contextflex-direction—row,row-reverse,column,column-reverseflex-wrap—nowrap(default),wrap,wrap-reversejustify-content—flex-start,flex-end,center,space-between,space-around,space-evenlyalign-items—stretch,flex-start,flex-end,center,baselinegap— spacing between flex items
On the items:
flex-grow— how much an item should grow relative to siblings (default: 0)flex-shrink— how much an item should shrink relative to siblings (default: 1)flex-basis— the initial size before growing or shrinkingalign-self— override alignment for a single itemorder— change the visual order without changing HTML
What Is CSS Grid?
CSS Grid is a two-dimensional layout system. It lets you define rows and columns simultaneously and place items into specific cells or areas of that grid. Where Flexbox handles one axis, Grid handles both axes at once, giving you precise control over where every item goes.
Grid is designed for layout at the page or component level, where you need to define the overall structure. You can create complex arrangements with overlapping items, spanning across multiple rows or columns, and named template areas that read almost like a visual blueprint of your layout.
Here is a basic Grid setup:
.grid-container {
display: grid;
grid-template-columns: 200px 1fr 200px; /* 3 columns */
grid-template-rows: auto 1fr auto; /* 3 rows */
gap: 1rem; /* Space between cells */
}
And here is the conceptual structure:
Column 1 Column 2 Column 3
(200px) (1fr) (200px)
┌────────────┬─────────────┬────────────┐
Row 1 │ Header │ Header │ Header │ (auto)
(auto) │ │ (spans 3) │ │
├────────────┼─────────────┼────────────┤
Row 2 │ │ │ │
(1fr) │ Sidebar │ Content │ Aside │
│ │ │ │
├────────────┼─────────────┼────────────┤
Row 3 │ Footer │ Footer │ Footer │ (auto)
(auto) │ │ (spans 3) │ │
└────────────┴─────────────┴────────────┘
With Grid, you define the structure first (the columns and rows), then place items into that structure. This is fundamentally different from Flexbox, where the items themselves determine how space is distributed.
Core Grid Properties
On the container:
display: grid— creates the grid formatting contextgrid-template-columns— defines column tracks (e.g.,1fr 2fr 1fr,repeat(3, 1fr))grid-template-rows— defines row tracksgrid-template-areas— defines named regions of the gridgap— spacing between grid cellsjustify-items— horizontal alignment of items within their cellsalign-items— vertical alignment of items within their cells
On the items:
grid-column— which column(s) the item occupies (e.g.,1 / 3to span two columns)grid-row— which row(s) the item occupiesgrid-area— shorthand for row/column placement, or a named area referencejustify-self— horizontal alignment for a single itemalign-self— vertical alignment for a single item
Key Differences: Flexbox vs Grid
The fundamental difference is dimensional: Flexbox is one-dimensional, Grid is two-dimensional. But the practical differences go much deeper than that. Here is a detailed comparison:
| Feature | Flexbox | Grid |
|---|---|---|
| Dimensions | One-dimensional (row OR column) | Two-dimensional (rows AND columns) |
| Layout approach | Content-driven (items determine size) | Structure-driven (grid defines placement) |
| Alignment | Along main axis + cross axis | Along both axes with cell-level control |
| Item sizing | flex-grow, flex-shrink, flex-basis | Track sizes (fr, px, %, minmax, auto) |
| Item overlap | Not supported natively | Items can overlap cells (z-index applies) |
| Named areas | No | Yes (grid-template-areas) |
| Spanning | No row/column spanning | Items can span rows and/or columns |
| Implicit tracks | Items wrap to new lines with flex-wrap | Implicit rows/columns auto-created as needed |
| Content reordering | order property on items | Place items anywhere on the grid |
| Best for | Components, inline layouts, distribution | Page layouts, complex arrangements, dashboards |
| Browser support | 99%+ (since 2015) | 98%+ (since 2017) |
When to Use Flexbox
Flexbox is the right choice when you are dealing with layout in a single direction and want items to adapt their size based on available space. Think of it as the tool for arranging things in a line. Here are the specific scenarios where Flexbox shines.
1. Navigation Bars
Navigation bars are the textbook Flexbox use case. You have a row of items, you want to spread them out or group them, and you want vertical centering. Flexbox handles this perfectly:
/* ┌─────────────────────────────────────────┐
│ Logo Home About Blog [Login] │
└─────────────────────────────────────────┘ */
.navbar {
display: flex;
align-items: center; /* Vertical centering */
padding: 0 2rem;
height: 60px;
}
.navbar .logo {
margin-right: auto; /* Push everything else to the right */
}
.navbar .nav-links {
display: flex;
gap: 1.5rem;
}
.navbar .login-btn {
margin-left: 2rem;
}
The margin-right: auto trick on the logo is pure Flexbox magic. It absorbs all remaining space, pushing the nav links and login button to the right side. You could also use justify-content: space-between on the parent, but the auto-margin approach gives you more granular control when you have three or more groups.
2. Centering Content
The famous "center a div" problem. Flexbox makes it trivial:
/* ┌─────────────────────────────────┐
│ │
│ ┌─────────────┐ │
│ │ Centered! │ │
│ └─────────────┘ │
│ │
└─────────────────────────────────┘ */
.center-container {
display: flex;
justify-content: center; /* Horizontal center */
align-items: center; /* Vertical center */
min-height: 100vh;
}
This works for any content: a single element, a login form, an error message, or a loading spinner. Three lines of CSS replace what used to require transforms, table-cell hacks, or absolute positioning tricks.
3. Button Groups and Toolbars
Groups of buttons, icon bars, or tags that sit in a row with consistent spacing:
/* ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐
│ Bold │ │Italic│ │Under │ │ Link │
└──────┘ └──────┘ └──────┘ └──────┘ */
.toolbar {
display: flex;
gap: 0.5rem;
flex-wrap: wrap; /* Wrap to next line on small screens */
}
.toolbar button {
flex: 0 0 auto; /* Do not grow or shrink */
}
4. Card Content Layout
Inside a card, Flexbox is perfect for stacking content vertically and pushing the footer to the bottom, regardless of how much content the card contains:
/* ┌──────────────────┐
│ Card Title │
│ Description │
│ text here... │
│ │
│ │
│ [Read More] │ ← always at bottom
└──────────────────┘ */
.card {
display: flex;
flex-direction: column;
height: 100%;
}
.card .content {
flex: 1; /* Grow to fill space */
}
.card .footer {
margin-top: auto; /* Push to bottom */
}
5. Form Layouts
Input fields with inline labels, or input groups with buttons attached:
/* ┌────────────────────┬──────────┐
│ Search... │ [Search] │
└────────────────────┴──────────┘ */
.input-group {
display: flex;
}
.input-group input {
flex: 1; /* Input takes remaining space */
border-radius: 6px 0 0 6px;
}
.input-group button {
flex: 0 0 auto; /* Button keeps its natural size */
border-radius: 0 6px 6px 0;
}
When to Use CSS Grid
Grid is the right choice when you need to control layout in two dimensions simultaneously, when you have a defined structure that items should fit into, or when items need to span multiple rows or columns. Here are the scenarios where Grid is clearly the better tool.
1. Page Layouts
The classic header, sidebar, content, footer arrangement is exactly what Grid was built for:
/* ┌──────────────────────────────────┐
│ Header │
├──────────┬───────────────────────┤
│ │ │
│ Sidebar │ Content │
│ │ │
├──────────┴───────────────────────┤
│ Footer │
└──────────────────────────────────┘ */
.page {
display: grid;
grid-template-areas:
"header header"
"sidebar content"
"footer footer";
grid-template-columns: 250px 1fr;
grid-template-rows: auto 1fr auto;
min-height: 100vh;
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.content { grid-area: content; }
.footer { grid-area: footer; }
The grid-template-areas property makes this layout self-documenting. You can literally see the structure in the CSS. Changing the layout for different screen sizes is as simple as redefining the template areas:
@media (max-width: 768px) {
.page {
grid-template-areas:
"header"
"content"
"sidebar"
"footer";
grid-template-columns: 1fr;
}
}
2. Card Grids
When you want cards in a uniform grid where all columns are the same width and all rows align neatly:
/* ┌──────────┐ ┌──────────┐ ┌──────────┐
│ Card 1 │ │ Card 2 │ │ Card 3 │
│ │ │ │ │ │
└──────────┘ └──────────┘ └──────────┘
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Card 4 │ │ Card 5 │ │ Card 6 │
│ │ │ │ │ │
└──────────┘ └──────────┘ └──────────┘ */
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 1.5rem;
}
The repeat(auto-fill, minmax(300px, 1fr)) pattern is one of the most useful CSS snippets in existence. It creates as many columns as will fit, each at least 300px wide, and distributes remaining space equally. The grid is fully responsive with zero media queries.
3. Dashboard Layouts
Dashboards with mixed-size widgets that span different numbers of rows and columns are a natural Grid use case:
/* ┌────────────────────┬──────────┐
│ │ Widget │
│ Main Chart │ B │
│ ├──────────┤
│ │ Widget │
├──────────┬─────────┤ C │
│ Widget D │Widget E │ │
└──────────┴─────────┴──────────┘ */
.dashboard {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(3, 200px);
gap: 1rem;
}
.main-chart {
grid-column: 1 / 3; /* Spans columns 1-2 */
grid-row: 1 / 3; /* Spans rows 1-2 */
}
.widget-b { grid-column: 3; grid-row: 1; }
.widget-c { grid-column: 3; grid-row: 2 / 4; }
.widget-d { grid-column: 1; grid-row: 3; }
.widget-e { grid-column: 2; grid-row: 3; }
4. Image Galleries
Photo galleries with a masonry-like effect where some images are larger than others:
.gallery {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-auto-rows: 200px;
gap: 0.5rem;
}
.gallery .featured {
grid-column: span 2;
grid-row: span 2;
}
.gallery img {
width: 100%;
height: 100%;
object-fit: cover;
border-radius: 8px;
}
5. Form Layouts with Labels and Fields
When form labels and inputs need to line up in a structured two-column grid:
/* ┌──────────┬─────────────────────┐
│ Name: │ [________________] │
├──────────┼─────────────────────┤
│ Email: │ [________________] │
├──────────┼─────────────────────┤
│ Bio: │ [________________] │
│ │ [ ] │
└──────────┴─────────────────────┘ */
.form-grid {
display: grid;
grid-template-columns: 120px 1fr;
gap: 1rem;
align-items: start;
}
.form-grid label {
text-align: right;
padding-top: 0.5rem;
}
Flexbox vs Grid: Real-World Layout Comparisons
Sometimes the choice between Flexbox and Grid is not obvious. Let us walk through several real-world layouts and analyze which approach works better and why.
Layout 1: A Row of Equal-Width Cards
Both Flexbox and Grid can produce a row of equal-width cards, but they approach it differently.
The Grid approach is cleaner for this:
/* Grid: clean and explicit */
.cards {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
}
/* Flexbox: works, but requires more thought */
.cards {
display: flex;
gap: 1rem;
}
.cards .card {
flex: 1 1 0; /* Equal width, but based on content */
}
Grid wins here because 1fr columns are truly equal regardless of content. With Flexbox's flex: 1 1 0, items start equal but can be influenced by min-content sizes. If one card has a very long word, it might end up wider. Grid enforces the column structure.
Layout 2: A Media Object (Image + Text Side by Side)
This is the classic media object: a fixed-width image on the left, text that fills remaining space on the right.
/* ┌──────┬────────────────────┐
│ │ Title │
│ img │ Description text │
│ │ that wraps... │
└──────┴────────────────────┘ */
/* Flexbox: natural and simple */
.media {
display: flex;
gap: 1rem;
align-items: flex-start;
}
.media img {
flex: 0 0 120px; /* Fixed width, no grow/shrink */
}
.media .body {
flex: 1; /* Fill remaining space */
}
/* Grid: also works well */
.media {
display: grid;
grid-template-columns: 120px 1fr;
gap: 1rem;
align-items: start;
}
Both work well here. Flexbox feels more natural because the layout is fundamentally one-dimensional (a row). The Grid version is slightly more code for the same result. For simple two-column component layouts like this, Flexbox is the more idiomatic choice.
Layout 3: A Responsive Gallery That Reflows
/* Grid: responsive with no media queries */
.gallery {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 1rem;
}
/* Flexbox: harder to get equal-width items */
.gallery {
display: flex;
flex-wrap: wrap;
gap: 1rem;
}
.gallery .item {
flex: 1 1 250px; /* Grows and shrinks, min 250px */
/* Problem: last row items stretch to fill */
}
Grid wins here decisively. The auto-fill / minmax pattern creates a perfectly responsive grid. Flexbox's flex-wrap approach has a well-known problem: if the last row has fewer items than the others, those items stretch to fill the entire row, creating uneven card widths. You would need extra invisible spacer elements or complex calculations to work around this. Grid does not have this issue.
Layout 4: A Header with Left, Center, and Right Groups
/* ┌──────┬────────────────┬──────────┐
│ Logo │ Nav Links │ [Login] │
└──────┴────────────────┴──────────┘ */
/* Grid: truly centered middle section */
.header {
display: grid;
grid-template-columns: auto 1fr auto;
align-items: center;
padding: 1rem;
}
.header .nav {
justify-self: center; /* Truly centered in the page */
}
/* Flexbox: center is only visual, not true center */
.header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem;
}
Grid wins for true centering. With Flexbox's space-between, the middle group is centered between the left and right groups, not centered on the page. If the logo is wider than the login button, the nav links shift slightly off-center. Grid's three-column approach with justify-self: center keeps the middle column perfectly centered regardless of the content in the outer columns.
Combining Flexbox and Grid
The best real-world layouts use both Flexbox and Grid together. They are complementary, not competing. The standard pattern is: Grid for the outer page structure, Flexbox for the inner component layout.
Example: Blog Layout
/* Grid for the page structure */
.page {
display: grid;
grid-template-columns: 1fr min(720px, 100%) 1fr;
grid-template-rows: auto 1fr auto;
}
.page > * {
grid-column: 2;
}
/* Flexbox for the header component inside the grid */
.page header {
grid-column: 1 / -1; /* Full width */
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem 2rem;
}
/* Flexbox for tag lists inside blog posts */
.post .tags {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
}
/* Flexbox for the author info block */
.post .author {
display: flex;
align-items: center;
gap: 1rem;
}
Example: E-Commerce Product Grid
/* Grid for the product listing */
.products {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 1.5rem;
}
/* Flexbox for each product card's internal layout */
.product-card {
display: flex;
flex-direction: column;
}
.product-card .image {
aspect-ratio: 4 / 3;
overflow: hidden;
}
.product-card .details {
flex: 1;
display: flex;
flex-direction: column;
padding: 1rem;
}
.product-card .price-row {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: auto; /* Push to bottom of card */
}
Notice the pattern: Grid defines where the cards go on the page, and Flexbox arranges the content within each card. This combination handles both the macro layout (card positions) and micro layout (content inside cards) cleanly.
Example: Dashboard with Flex-Based Widgets
/* Grid for the dashboard layout */
.dashboard {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-auto-rows: minmax(200px, auto);
gap: 1rem;
padding: 1rem;
}
.widget-large { grid-column: span 2; grid-row: span 2; }
.widget-wide { grid-column: span 2; }
.widget-tall { grid-row: span 2; }
/* Flexbox for widget internals */
.widget {
display: flex;
flex-direction: column;
background: #1a1d27;
border-radius: 8px;
padding: 1.5rem;
}
.widget .header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1rem;
}
.widget .body {
flex: 1; /* Content fills available space */
}
.widget .footer {
display: flex;
gap: 0.5rem;
margin-top: auto; /* Stick to bottom */
}
Common Layout Patterns and Which to Use
Here is a quick-reference guide for the most common layout patterns developers encounter. Each recommendation is based on which system produces the cleanest, most maintainable code for that specific pattern.
Use Flexbox For:
- Navigation bars — horizontal row with vertical centering, space distribution
- Centering a single element — the three-line centering pattern
- Button groups and toolbars — a row of equally-spaced interactive elements
- Media objects — image with text beside it
- Card internals — stacking title, description, and CTA vertically
- Input groups — input field with attached button
- Breadcrumbs and tag lists — wrapping inline elements
- Sticky footers in cards — pushing an element to the bottom with
margin-top: auto - Vertical stacking —
flex-direction: columnfor simple vertical layouts - Equal-height columns — by default, flex items in a row stretch to the tallest item
Use Grid For:
- Page layouts — header, sidebar, content, footer arrangements
- Card grids — uniform responsive grids with
auto-fill/minmax - Dashboards — mixed-size widgets spanning rows and columns
- Image galleries — items that span multiple cells
- Form layouts — label-input pairs in a structured two-column grid
- Magazine layouts — asymmetric content placement with named areas
- Overlapping elements — layering items in the same grid cell
- Holy grail layout — the classic three-column layout with header and footer
- Auto-responsive layouts — using
repeat(auto-fill, minmax(...))for no-media-query responsive design - Truly centered three-column headers — where the center must be page-centered regardless of side widths
Advanced Patterns
Subgrid: Grid's Most Powerful Addition
CSS Subgrid, now supported in all major browsers, solves a problem that was previously impossible: aligning nested grid items to the parent grid's tracks. Without subgrid, a card's internal elements cannot align with elements in sibling cards.
/* Without subgrid, each card's content aligns independently:
┌────────────────┐ ┌────────────────┐
│ Short Title │ │ A Much Longer │
│────────────────│ │ Title Here │
│ Description │ │────────────────│
│ │ │ Description │
│ [Button] │ │ [Button] │
└────────────────┘ └────────────────┘
▲ Titles don't align across cards!
With subgrid:
┌────────────────┐ ┌────────────────┐
│ Short Title │ │ A Much Longer │
│ │ │ Title Here │
│────────────────│ │────────────────│ ← aligned!
│ Description │ │ Description │
│ [Button] │ │ [Button] │
└────────────────┘ └────────────────┘ */
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 1.5rem;
}
.card {
display: grid;
grid-template-rows: subgrid; /* Inherit parent row tracks */
grid-row: span 3; /* Each card spans 3 rows */
gap: 0.75rem;
}
Subgrid is one of the strongest reasons to choose Grid for card layouts in 2026. It ensures visual consistency across cards with varying content lengths.
Container Queries with Grid and Flexbox
Container queries (available in all major browsers since 2023) pair beautifully with both layout systems. Instead of checking the viewport width, you check the container's width, letting a component adapt based on where it is placed:
.card-container {
container-type: inline-size;
}
/* Default: Flexbox column layout for narrow containers */
.card {
display: flex;
flex-direction: column;
}
/* Switch to Grid layout when the container is wide enough */
@container (min-width: 500px) {
.card {
display: grid;
grid-template-columns: 200px 1fr;
grid-template-rows: auto 1fr;
}
.card .image {
grid-row: 1 / -1;
}
}
This pattern lets a component use Flexbox when it is in a narrow sidebar and Grid when it has more room in the main content area, with zero JavaScript.
The Responsive Sidebar Pattern
A common pattern that elegantly combines Grid and Flexbox:
/* Grid for the sidebar-content split */
.layout {
display: grid;
grid-template-columns: minmax(200px, 25%) 1fr;
min-height: 100vh;
}
/* Collapse sidebar on small screens */
@media (max-width: 768px) {
.layout {
grid-template-columns: 1fr;
}
}
/* Flexbox for the sidebar's internal navigation */
.sidebar nav {
display: flex;
flex-direction: column;
gap: 0.25rem;
padding: 1rem;
}
.sidebar nav a {
display: flex;
align-items: center;
gap: 0.75rem;
padding: 0.5rem 0.75rem;
border-radius: 6px;
}
.sidebar nav a:hover {
background: rgba(255, 255, 255, 0.05);
}
Common Mistakes to Avoid
1. Using Grid for One-Dimensional Layouts
If you only need items in a row or a column, Flexbox is simpler and more appropriate:
/* Overkill: Grid for a simple button row */
.buttons {
display: grid;
grid-template-columns: auto auto auto;
gap: 0.5rem;
}
/* Better: Flexbox is designed for this */
.buttons {
display: flex;
gap: 0.5rem;
}
2. Fighting Flexbox for Grid's Job
If you are using multiple Flexbox containers nested inside each other to create a two-dimensional layout, you probably want Grid:
/* Struggling: nested Flexbox to simulate a grid */
.container {
display: flex;
flex-wrap: wrap;
}
.container .item {
flex: 0 0 calc(33.333% - 1rem);
margin: 0.5rem;
}
/* Cleaner: Grid was built for this */
.container {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
}
3. Forgetting flex-shrink Defaults
By default, flex-shrink is 1, which means items will shrink below their natural size if the container is too small. This often causes unexpected text wrapping or squished elements. Set flex-shrink: 0 on items that should never shrink:
.sidebar {
flex: 0 0 250px; /* Do NOT grow, do NOT shrink, start at 250px */
}
4. Using Percentage Widths Inside Flex Containers
Percentage widths and flex properties can conflict. Prefer flex-basis over width inside flex containers:
/* Fragile: mixing width and flex */
.item {
width: 50%;
flex: 1; /* Conflicts with width */
}
/* Better: use flex-basis */
.item {
flex: 1 1 50%; /* grow, shrink, basis */
}
5. Not Using the gap Property
Before gap was supported in Flexbox (it landed in all major browsers in 2021), developers used margins for spacing. There is no reason to do this anymore. gap works on both Flexbox and Grid and is cleaner because it does not create extra margin on the outer edges:
/* Old: margin-based spacing (first/last child issues) */
.items .item {
margin-right: 1rem;
}
.items .item:last-child {
margin-right: 0;
}
/* Modern: gap handles it */
.items {
display: flex;
gap: 1rem;
}
Performance Considerations
Both Flexbox and Grid are hardware-accelerated in modern browsers and perform extremely well. However, there are a few nuances worth knowing:
- Flexbox is marginally faster for simple one-dimensional layouts because the browser only needs to calculate distribution along one axis. The difference is negligible for most layouts but can be measurable in lists with thousands of items.
- Grid layout calculations can be more complex when using features like
minmax,auto-fill, or subgrid, because the browser must resolve both dimensions simultaneously. Again, this is rarely a bottleneck in practice. - Avoid deeply nested flex/grid containers. Each nesting level adds layout calculations. If you have flex containers inside flex containers inside grid containers, reconsider the structure.
- Use
content-visibility: autofor long lists or grids that extend below the fold. This tells the browser to skip layout calculations for off-screen items.
For the vast majority of layouts, choose between Flexbox and Grid based on semantic fit and code clarity, not performance. The difference in render time between the two is typically less than a millisecond.
Decision Framework: A Quick Guide
When you are staring at a design and wondering which layout system to use, run through this checklist:
- Is the layout one-dimensional? (Items in a row or a column) Use Flexbox.
- Is the layout two-dimensional? (Rows and columns matter) Use Grid.
- Are items' sizes driving the layout? (Content determines structure) Use Flexbox.
- Is the structure driving item placement? (Grid defines where things go) Use Grid.
- Do items need to span multiple rows or columns? Use Grid.
- Do you need items to overlap? Use Grid.
- Is it a component's internal layout? (Nav, card, toolbar) Likely Flexbox.
- Is it the outer page structure? (Header, sidebar, content, footer) Likely Grid.
- Do you need named template areas? Use Grid.
- Is it a simple centering task? Either works, but Flexbox is slightly less code.
When in doubt, start with Flexbox for components and Grid for layouts. If you find yourself fighting Flexbox (percentage hacks, nested wrappers, last-row issues), switch to Grid. If Grid feels like overkill for a simple row of items, switch to Flexbox.
Summary
Flexbox and CSS Grid are not competitors. They are complementary tools designed for different problems. Flexbox handles one-dimensional distribution of items along a single axis. Grid handles two-dimensional placement of items into a defined structure. The most effective CSS in production codebases uses both, often on the same page: Grid for the page skeleton and Flexbox for the components that live inside it.
In 2026, there is no browser support concern for either system. Both are universally available. The decision comes down to the nature of the layout you are building. Use the right tool for the job, and your CSS will be shorter, more readable, and easier to maintain.
If you are learning these systems hands-on, experiment with our CSS Flexbox Generator to see how each property affects item layout in real time. Keep our Flexbox and Grid cheat sheets open as quick references. The best way to internalize the differences is to build real layouts with both and observe where each one clicks.