The Core Difference: One vs Two Dimensions
The fundamental difference between Flexbox and Grid comes down to dimensions. Flexbox is one-dimensional: it lays out items along a single axis (either a row or a column). Grid is two-dimensional: it controls both rows and columns at the same time.
This is not a quality judgment. A navigation bar is inherently one-dimensional — items flow in a row. A dashboard layout is inherently two-dimensional — content needs to align both horizontally and vertically. The layout dictates the tool.
If your layout works as a line of items (even if that line wraps), use Flexbox. If your layout needs items to align in both rows and columns simultaneously, use Grid. If you are unsure, start with Flexbox — you can always refactor to Grid if alignment across both axes becomes a problem.
Flexbox Essentials
Flexbox works with two types of elements: the flex container (the parent with display: flex) and the flex items (the direct children). The container controls the overall flow, and items can control their own sizing and alignment within that flow.
.container {
display: flex;
/* Direction: row (default), row-reverse, column, column-reverse */
flex-direction: row;
/* Wrapping: nowrap (default), wrap, wrap-reverse */
flex-wrap: wrap;
/* Main axis alignment */
justify-content: flex-start; /* start (default) */
justify-content: center; /* center items */
justify-content: space-between;/* equal space between items */
justify-content: space-around; /* equal space around items */
justify-content: space-evenly; /* truly equal spacing */
/* Cross axis alignment */
align-items: stretch; /* fill height (default) */
align-items: flex-start; /* top align */
align-items: center; /* center vertically */
align-items: flex-end; /* bottom align */
align-items: baseline; /* align by text baseline */
/* Gap between items */
gap: 16px; /* row and column gap */
row-gap: 16px; /* only row gap */
column-gap: 24px; /* only column gap */
}
.item {
/* How much the item grows relative to siblings */
flex-grow: 1; /* take up available space */
flex-grow: 0; /* do not grow (default) */
/* How much the item shrinks when space is tight */
flex-shrink: 1; /* allow shrinking (default) */
flex-shrink: 0; /* do not shrink */
/* Base size before growing/shrinking */
flex-basis: auto; /* use width/height (default) */
flex-basis: 200px; /* start at 200px */
flex-basis: 0; /* ignore content size, distribute space evenly */
/* Shorthand: grow shrink basis */
flex: 1; /* flex: 1 1 0% — grow, shrink, ignore content size */
flex: 0 0 auto; /* no grow, no shrink, use content size */
/* Override container's align-items for this item */
align-self: center;
/* Change visual order without changing DOM order */
order: -1; /* move to the front */
}
You can experiment with all of these properties interactively in the Flexbox Playground — adjust values and see the result in real time without writing code.
Grid Essentials
Grid introduces a coordinate system. You define rows and columns on the container, and items can be placed into specific cells or allowed to flow automatically.
.container {
display: grid;
/* Define columns */
grid-template-columns: 200px 1fr 200px; /* fixed-flexible-fixed */
grid-template-columns: repeat(3, 1fr); /* three equal columns */
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); /* responsive */
/* Define rows */
grid-template-rows: auto 1fr auto; /* header-content-footer */
grid-auto-rows: minmax(100px, auto); /* implicit row sizing */
/* Named areas (visual layout) */
grid-template-areas:
"header header header"
"sidebar content aside"
"footer footer footer";
/* Gaps */
gap: 16px;
row-gap: 16px;
column-gap: 24px;
/* Alignment of all items within their cells */
justify-items: stretch; /* fill cell width (default) */
align-items: stretch; /* fill cell height (default) */
/* Alignment of the entire grid within the container */
justify-content: center; /* center grid horizontally */
align-content: center; /* center grid vertically */
}
.item {
/* Place by line numbers */
grid-column: 1 / 3; /* span columns 1 to 3 */
grid-row: 2 / 4; /* span rows 2 to 4 */
/* Place by named area */
grid-area: header; /* matches grid-template-areas name */
/* Span multiple cells */
grid-column: span 2; /* span 2 columns from auto position */
grid-row: span 3; /* span 3 rows */
/* Self-alignment within the cell */
justify-self: center; /* center horizontally in cell */
align-self: end; /* align to bottom of cell */
}
The CSS Grid Playground lets you define grid tracks, place items, and see the result immediately. It is the fastest way to prototype grid layouts before writing the final CSS.
Side-by-Side Comparison
| Feature | Flexbox | Grid |
|---|---|---|
| Layout dimension | One-dimensional (row OR column) | Two-dimensional (row AND column) |
| Content vs layout | Content-driven (items size themselves) | Layout-driven (grid defines the structure) |
| Item placement | Items flow in order, wrapping when needed | Items can be placed in any cell explicitly |
| Overlap | Not possible without position hacks | Items can overlap by occupying the same cells |
| Named areas | Not available | grid-template-areas for visual layout definition |
| Subgrid | Not available | Child grids inherit parent track sizes |
| Implicit tracks | Items wrap to new lines automatically | New rows/columns created automatically for overflow |
| Gap support | Yes (gap, row-gap, column-gap) | Yes (gap, row-gap, column-gap) |
| Browser support | 97%+ (since 2013) | 97%+ (since 2017, subgrid since 2023) |
When to Use Flexbox
Flexbox is the right choice when items flow along a single axis and their sizes should be driven by their content.
Navigation Bars
.navbar {
display: flex;
align-items: center;
gap: 24px;
padding: 0 24px;
height: 64px;
}
.navbar-logo {
margin-right: auto; /* pushes everything else to the right */
}
.navbar-link {
white-space: nowrap;
}
The margin-right: auto trick on the logo pushes all nav links to the right side. This is a Flexbox-only pattern that is cleaner than any Grid alternative.
Centering Content
/* The simplest way to center anything */
.center {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
Form Layouts
.search-form {
display: flex;
gap: 8px;
}
.search-input {
flex: 1; /* takes all available space */
min-width: 0; /* allows shrinking below content size */
}
.search-button {
flex-shrink: 0; /* never shrink the button */
}
Other Flexbox Use Cases
- Toolbars and button groups
- Vertical stacking with variable spacing (column direction)
- Media objects (icon + text side by side)
- Equal-height cards in a single row
- Footer with items pushed to opposite ends
When to Use Grid
Grid is the right choice when items need to align in both directions or when you want the layout structure to be independent of the content.
Card Grids
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 24px;
}
/* Each card fills its cell — no extra sizing needed */
.card {
background: var(--surface);
border-radius: 12px;
padding: 24px;
}
This single CSS rule creates a responsive grid that adapts from 1 column on mobile to 2, 3, or 4 columns on wider screens without any media queries. Each card is the same width within its row.
Page Layout (Holy Grail)
.page {
display: grid;
grid-template-areas:
"header header header"
"sidebar content aside"
"footer footer footer";
grid-template-columns: 240px 1fr 200px;
grid-template-rows: auto 1fr auto;
min-height: 100vh;
gap: 0;
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.content { grid-area: content; }
.aside { grid-area: aside; }
.footer { grid-area: footer; }
/* Responsive: collapse to single column */
@media (max-width: 768px) {
.page {
grid-template-areas:
"header"
"content"
"sidebar"
"aside"
"footer";
grid-template-columns: 1fr;
}
}
Named grid areas make the layout immediately readable. The visual ASCII-art pattern in grid-template-areas maps directly to the page structure. Rearranging for mobile takes one media query.
Dashboard Layout
.dashboard {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-auto-rows: minmax(200px, auto);
gap: 16px;
}
.widget-large {
grid-column: span 2;
grid-row: span 2;
}
.widget-wide {
grid-column: span 2;
}
.widget-tall {
grid-row: span 2;
}
Other Grid Use Cases
- Image galleries with consistent sizing
- Pricing tables
- Feature comparison grids
- Magazine-style layouts with overlapping content
- Calendar and schedule views
When converting your Grid layouts to utility-class frameworks, the CSS to Tailwind Converter translates grid-template-columns, gap, and placement properties to their Tailwind equivalents.
Build Layouts Visually, Copy the CSS
QTool has free Flexbox and Grid playgrounds. Drag, adjust, and export production-ready CSS without writing a line of code.
Flexbox Playground Grid PlaygroundCombining Flexbox and Grid
The most effective layouts use both. Grid handles the macro layout (page sections), and Flexbox handles the micro layout (content inside each section).
/* Grid: page structure */
.page {
display: grid;
grid-template-columns: 1fr;
grid-template-rows: auto 1fr auto;
min-height: 100vh;
}
/* Flexbox: header navigation */
.header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 24px;
height: 64px;
}
/* Grid: main content area */
.main {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 24px;
padding: 24px;
}
/* Flexbox: individual card */
.card {
display: flex;
flex-direction: column;
gap: 12px;
}
.card-footer {
margin-top: auto; /* pushes footer to bottom of card */
display: flex;
justify-content: space-between;
align-items: center;
}
/* Flexbox: footer */
.footer {
display: flex;
justify-content: center;
gap: 24px;
padding: 24px;
}
In this layout:
- Grid defines the page skeleton (header/main/footer) and the card grid
- Flexbox arranges the header navigation, card internals, and footer links
There is no conflict between them. A grid item is a flex container. A flex item can contain a grid. They nest cleanly.
Responsive Patterns Without Media Queries
Both Flexbox and Grid can create responsive layouts that adapt to container width without a single @media rule.
Grid: auto-fill vs auto-fit
/* auto-fill: creates empty columns if space allows */
.grid-fill {
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
}
/* On a 900px container with 200px min: 4 columns (1 might be empty) */
/* auto-fit: collapses empty columns, items stretch */
.grid-fit {
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}
/* On a 900px container with 2 items: items stretch to fill */
Use auto-fill when you want consistent column widths regardless of item count. Use auto-fit when you want items to stretch and fill the available space.
Flexbox: Wrapping with Minimum Widths
.flex-responsive {
display: flex;
flex-wrap: wrap;
gap: 16px;
}
.flex-responsive > * {
flex: 1 1 300px; /* grow, shrink, minimum 300px */
min-width: 0; /* allow shrinking below content size */
}
/* Items are at least 300px wide. On narrow screens they stack.
On wide screens they sit side by side and grow equally. */
Container Queries (Modern Approach)
.card-container {
container-type: inline-size;
}
.card {
display: flex;
flex-direction: column;
}
/* When the container (not the viewport) is wide enough */
@container (min-width: 500px) {
.card {
flex-direction: row;
align-items: center;
gap: 24px;
}
}
Container queries respond to the element's container size rather than the viewport. This makes components truly reusable regardless of where they appear on the page. Combined with auto-fill grids, you can build entire responsive pages with zero viewport media queries.
To verify how your layouts render at different screen sizes, the Responsive Tester previews any URL at common device widths simultaneously.
Common Layout Recipes
Sticky Footer
/* Grid approach */
body {
display: grid;
grid-template-rows: auto 1fr auto;
min-height: 100vh;
}
/* Flexbox approach */
body {
display: flex;
flex-direction: column;
min-height: 100vh;
}
main {
flex: 1; /* main content takes all available space */
}
Sidebar Layout
.layout {
display: grid;
grid-template-columns: 280px 1fr;
height: 100vh;
}
.sidebar {
overflow-y: auto;
border-right: 1px solid var(--border);
padding: 24px;
}
.main-content {
overflow-y: auto;
padding: 24px;
}
@media (max-width: 768px) {
.layout {
grid-template-columns: 1fr;
}
.sidebar {
display: none; /* or toggle with JS */
}
}
Masonry-Style (CSS Grid)
.masonry {
columns: 3;
column-gap: 16px;
}
.masonry-item {
break-inside: avoid;
margin-bottom: 16px;
}
/* True CSS masonry (Chrome 128+, Firefox behind flag) */
.masonry-native {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
grid-template-rows: masonry;
gap: 16px;
}
Native CSS masonry via grid-template-rows: masonry is shipping in major browsers throughout 2026. Until full support lands, the CSS columns property or a JavaScript library like Masonry.js are the reliable fallbacks. Check Can I Use for current support.
Performance Considerations
For the vast majority of web pages, Flexbox and Grid performance is identical and not a bottleneck. Layout calculations happen in microseconds. But if you are building applications with thousands of DOM elements (data tables, virtual lists, complex dashboards), a few things matter:
- Nested Flexbox is slower than flat Grid. If you are using multiple layers of nested flex containers to simulate a two-dimensional layout, a single Grid container will be faster because it resolves sizes in one pass instead of propagating constraints through nested containers.
- Grid with named areas has zero overhead. The
grid-template-areassyntax is purely declarative and does not add computational cost compared to line-number placement. - auto-fill/auto-fit grids are well-optimized. The browser does not re-layout on every pixel of resize — it recalculates only when the number of columns changes.
- The
gapproperty is faster than margins. Both in Flexbox and Grid,gapis applied during layout calculation. Margins require additional collapse/overlap resolution. - Avoid layout thrashing. Reading layout properties (offsetWidth, getBoundingClientRect) after DOM changes forces synchronous layout. This is the real performance killer in layout-heavy applications, regardless of whether you use Flexbox or Grid.
When converting your CSS to frameworks like Tailwind, the CSS Unit Converter helps translate between px, rem, em, and viewport units to maintain consistent sizing.
CSS Layout Tools
Frequently Asked Questions
Use Flexbox when your layout flows in one direction (a row of navigation links, a column of form fields, or a toolbar with items that need flexible spacing). Use Grid when you need to control placement in both rows and columns simultaneously (page layouts, card grids with consistent sizing, dashboards, or any layout where items need to align to a two-dimensional grid). In practice, most pages use both: Grid for the overall page structure and Flexbox for the components inside each grid area. They are complementary tools, not competitors.
For most real-world layouts, the performance difference between Grid and Flexbox is negligible. Both are highly optimized in modern browsers. Grid can be slightly faster for complex two-dimensional layouts because it calculates row and column sizes in a single pass, while achieving the same layout with nested Flexbox containers requires multiple layout passes. Flexbox can be marginally faster for simple one-dimensional layouts because it has fewer constraints to resolve. The performance difference only becomes measurable with thousands of elements on screen simultaneously. Choose based on which model fits your layout, not on micro-benchmarks.
Yes, and this is the recommended approach. Grid and Flexbox solve different problems and work well together. A common pattern is using Grid for the overall page layout (header, sidebar, main content, footer) and Flexbox for arranging items within each section (navigation links in the header, cards within the main content area, icon groups in the footer). A grid item can itself be a flex container, and a flex item can be a grid container. There is no conflict between them. Use each where it is the natural fit.
Both Flexbox and Grid use the same alignment properties (justify-content, align-items, align-self, gap), but they apply them differently. In Flexbox, justify-content distributes space along the main axis (the direction items flow) and align-items aligns items along the cross axis. In Grid, justify-content and align-content distribute space for the entire grid within its container, while justify-items and align-items control how items sit within their grid cells. Grid also has place-items and place-content shorthands that set both axes at once. The key difference is that Flexbox alignment is relative to the flex direction (which can change), while Grid alignment is always relative to the row and column axes.
Yes. As of 2026, CSS Grid has full support in every modern browser including Chrome, Firefox, Safari, Edge, and all Chromium-based browsers. Global browser support exceeds 97% according to Can I Use data. The original Grid specification has been supported since 2017. Newer features like subgrid are supported in Firefox (since 2019), Chrome and Edge (since 2023), and Safari (since 2022). The only browsers without Grid support are Internet Explorer 11 and older, which are no longer maintained. You can use CSS Grid in production without any polyfills or fallbacks for modern browser targets.
Use grid-template-columns with auto-fill or auto-fit and the minmax() function. The pattern grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)) creates a grid that automatically adjusts the number of columns based on the container width. Each column is at least 250px wide and grows equally to fill available space. auto-fill creates empty columns if there is extra space, while auto-fit collapses empty columns so existing items stretch to fill the row. This single line of CSS replaces multiple media queries and works for card grids, image galleries, product listings, and any layout where items should wrap responsively. For finer control, combine minmax with clamp() or container queries.