CSS layout has transformed over the past decade. Float-based layouts required hacky workarounds. Flexbox solved one-dimensional alignment. CSS Grid made complex two-dimensional layouts straightforward. Together they cover virtually every layout need.
Flexbox vs Grid — when to use each
Use Flexbox for:
- One-dimensional layouts (items in a row or a column)
- Navigation bars and toolbars
- Centering content vertically and horizontally
- Distributing items with flexible sizing along one axis
- Components where items need to grow or shrink based on content
Use Grid for:
- Two-dimensional layouts (controlling both rows and columns)
- Page-level layouts (header, sidebar, main, footer)
- Card grids and galleries
- Any design where elements need to align across both axes
- Complex overlapping or asymmetric layouts
The practical rule: Use Flexbox inside components, Grid for page structure. They complement each other — it's common to have a Grid page layout containing Flex components.
Essential Flexbox properties
Container
.container {
display: flex;
flex-direction: row; /* row | column | row-reverse | column-reverse */
flex-wrap: wrap; /* nowrap | wrap | wrap-reverse */
justify-content: space-between; /* main axis alignment */
align-items: center; /* cross axis alignment */
gap: 16px; /* space between items (replaces margin hacks) */
}
Items
.item {
flex: 1; /* shorthand: flex-grow flex-shrink flex-basis */
flex-grow: 1; /* how much item grows relative to siblings */
flex-shrink: 0; /* prevent shrinking below flex-basis */
flex-basis: 200px; /* starting size before grow/shrink applies */
align-self: flex-start; /* override align-items for this item only */
}
Essential CSS Grid properties
Container
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr); /* 3 equal columns */
grid-template-rows: auto 1fr auto; /* header, flexible main, footer */
gap: 24px;
justify-items: stretch; /* align items within their cells */
align-items: start;
}
Responsive grid without media queries
.responsive-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 16px;
}
This creates as many columns as fit while keeping each at least 200px wide — no media queries needed.
Item placement and spanning
.wide-item {
grid-column: span 2; /* spans 2 columns */
grid-row: span 2; /* spans 2 rows */
}
.header {
grid-column: 1 / -1; /* spans all columns */
}
Common layout patterns
Centering (the classic challenge, now trivial)
.centered {
display: flex;
align-items: center;
justify-content: center;
min-height: 100vh;
}
Holy Grail layout
.page {
display: grid;
grid-template-columns: 250px 1fr;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"header header"
"sidebar main"
"footer footer";
min-height: 100vh;
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.footer { grid-area: footer; }
Card grid with auto-fill
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 24px;
}
Nav bar (logo left, links right)
.nav {
display: flex;
justify-content: space-between;
align-items: center;
gap: 16px;
}
Common mistakes
- Using Flexbox for grid-like layouts (use Grid instead)
- Forgetting
min-width: 0on flex children that contain text (causes overflow) - Using
gapin Flexbox and not accounting for wrap behavior - Setting explicit row heights that break when content grows
- Overusing
position: absolutewhen Grid placement would work better
How to generate CSS layouts free
- Go to CSS Layout Generator
- Switch between Flexbox and Grid modes
- Adjust all properties using toggles and sliders
- See a live colored preview update instantly
- Load common layout presets (Holy Grail, Card Grid, Nav Bar, etc.)
- Copy the generated CSS or download as a
.cssfile
The one-dimension rule
Most Flexbox-versus-Grid confusion dissolves with a single question: are you laying out along one axis or two?
Flexbox is one-dimensional. It arranges items in a row or a column, and each line is sized independently. Grid is two-dimensional — rows and columns exist simultaneously, and a cell's position is defined in both at once.
The practical tell: if you find yourself trying to align an item in a flex row with an item in the flex row below it, you want Grid. Flex lines do not know about each other, so column alignment across wrapped rows is not something Flexbox can do.
Conversely, if you are laying out a navigation bar or a row of buttons, Grid's machinery is overhead you do not need.
The min-width: auto trap
This is the most common Flexbox bug and the hardest to diagnose, because nothing in your CSS mentions it.
A flex item has an implicit min-width: auto, meaning it will not shrink below its content's intrinsic size. A long unbroken string — a URL, a code sample, a German compound noun — forces the item wider than its container, and the layout overflows horizontally.
.flex-item {
min-width: 0; /* allow shrinking below content size */
overflow-wrap: anywhere;
}
The equivalent in a column direction is min-height: 0. If a flex or grid child is overflowing and you cannot see why, this is almost always the cause.
Intrinsic sizing without media queries
Grid can produce responsive layouts with no breakpoints at all:
.cards {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 1rem;
}
The container fits as many 250px-minimum columns as space allows, then distributes the remainder equally. Resizing reflows automatically.
auto-fill versus auto-fit is the detail people miss: auto-fill keeps empty tracks in the grid, while auto-fit collapses them so existing items stretch to fill the row. With three cards in a wide container, auto-fill leaves them at their minimum width with empty space to the right; auto-fit expands them across the full width.
gap replaced margin hacks
Before gap, spacing between items meant margins on children plus a negative margin on the container to cancel the outer edges. gap applies only between items, so no correction is needed.
It works in Grid, Flexbox, and multi-column layouts, and is supported everywhere current. If you are still writing .item + .item { margin-left: 1rem }, gap is simpler and handles wrapping correctly.
Logical properties
Physical directions break in right-to-left languages. margin-left stays on the left in Arabic, where it should mirror.
Logical properties follow writing direction instead:
| Physical | Logical |
|---|---|
margin-left |
margin-inline-start |
padding-top |
padding-block-start |
width |
inline-size |
text-align: left |
text-align: start |
Using them means a layout mirrors correctly by changing dir="rtl" alone. Worth adopting even for a single-language site, since retrofitting later is tedious.
Frequently asked questions
Should I use Grid for everything?
No. Grid for page and section structure, Flexbox for component internals — a button row, a card's header, a nav. Most real layouts nest both.
Why is my grid item overflowing its cell?
Usually the min-width: auto behaviour above. Grid items have the same implicit minimum as flex items.
Is float ever still needed?
Only for wrapping text around an image, which is what it was designed for. For layout it has been superseded entirely.
How do I centre something now?
display: grid; place-items: center on the parent. Two properties, works for any content size — the problem that once needed absolute positioning and transforms.
Does Grid affect accessibility?
It can. order and grid-area change visual position without changing DOM order, so keyboard focus and screen-reader sequence follow the source, not the screen. Keep visual and DOM order aligned where possible.