CSS Flexbox (Flexible Box Layout) is the most practical layout tool in modern CSS. It solves the problems that plagued developers for years — vertical centering, equal-height columns, distributing space evenly — with a clean, declarative syntax. This guide covers every flexbox property with examples you can adapt directly into your projects.
How Flexbox Works: The Mental Model
Flexbox operates on two axes: a main axis and a cross axis. By default, the main axis runs horizontally (left to right), and the cross axis runs vertically (top to bottom). When you change flex-direction to column, the axes flip.
Every flexbox layout has two types of elements:
- A flex container — the parent element with
display: flex - Flex items — the direct children of that container
Properties on the container control how items are laid out. Properties on items control how individual items behave within that layout.
Flex Container Properties
display: flex
The starting point for any flexbox layout. This turns an element into a flex container and its direct children into flex items.
.container {
display: flex; /* block-level flex container */
/* display: inline-flex; */ /* inline-level flex container */
}
flex-direction
Defines the main axis — the direction flex items are placed in the container.
.container {
flex-direction: row; /* default: left to right */
flex-direction: row-reverse; /* right to left */
flex-direction: column; /* top to bottom */
flex-direction: column-reverse; /* bottom to top */
}
flex-wrap
By default, flex items try to fit in a single line. flex-wrap controls whether items wrap to new lines.
.container {
flex-wrap: nowrap; /* default: single line, may overflow */
flex-wrap: wrap; /* wrap onto multiple lines */
flex-wrap: wrap-reverse; /* wrap onto multiple lines, reversed */
}
flex-flow (shorthand)
/* flex-flow: <flex-direction> <flex-wrap> */
.container {
flex-flow: row wrap;
flex-flow: column nowrap;
}
justify-content
Aligns items along the main axis. This is how you distribute leftover space horizontally (or vertically when direction is column).
.container {
justify-content: flex-start; /* default: pack items to start */
justify-content: flex-end; /* pack items to end */
justify-content: center; /* center items */
justify-content: space-between; /* first item at start, last at end, equal gaps */
justify-content: space-around; /* equal space around each item */
justify-content: space-evenly; /* equal space between all items including edges */
}
space-between is the most common choice for navigation bars and card grids. center is your one-liner for horizontal centering.
align-items
Aligns items along the cross axis. For a row container, this controls vertical alignment.
.container {
align-items: stretch; /* default: items stretch to fill container height */
align-items: flex-start; /* items align to start of cross axis */
align-items: flex-end; /* items align to end of cross axis */
align-items: center; /* items are centered on cross axis */
align-items: baseline; /* items align by their text baseline */
}
The classic "vertically center anything" trick uses both justify-content and align-items:
.centered {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
align-content
Controls spacing between rows of wrapped items on the cross axis. Only has an effect when items wrap onto multiple lines.
.container {
flex-wrap: wrap;
align-content: flex-start; /* rows packed to start */
align-content: flex-end; /* rows packed to end */
align-content: center; /* rows centered */
align-content: space-between; /* rows spread out */
align-content: space-around; /* equal space around rows */
align-content: stretch; /* default: rows stretch */
}
gap (formerly grid-gap)
gap creates space between flex items without needing margins. It's supported in all modern browsers and is cleaner than the old margin-based approach.
.container {
display: flex;
gap: 16px; /* same gap in both directions */
gap: 16px 24px; /* row-gap column-gap */
row-gap: 16px;
column-gap: 24px;
}
Flex Item Properties
flex-grow
Controls how much a flex item grows relative to others when there is leftover space. The default is 0 (don't grow). A value of 1 means the item will take up all available space.
.sidebar { flex-grow: 0; width: 250px; } /* fixed width */
.main { flex-grow: 1; } /* takes all remaining space */
/* Two items growing at different rates */
.col-a { flex-grow: 1; } /* gets 1/3 of extra space */
.col-b { flex-grow: 2; } /* gets 2/3 of extra space */
flex-shrink
Controls how much an item shrinks when there's not enough space. Default is 1 (items will shrink equally). Set to 0 to prevent shrinking.
.logo {
flex-shrink: 0; /* Never shrink the logo */
width: 120px;
}
.nav-links {
flex-shrink: 1; /* Can shrink if needed */
}
flex-basis
Sets the initial main size of a flex item before grow/shrink calculations. Think of it as the "ideal size" before flex kicks in.
.item {
flex-basis: auto; /* default: use width/height */
flex-basis: 200px; /* start at 200px then grow/shrink */
flex-basis: 25%; /* start at 25% of container */
flex-basis: 0; /* start at 0, let flex-grow distribute all space */
}
flex (shorthand)
The flex shorthand combines grow, shrink, and basis. This is what you'll use in practice.
/* flex: <flex-grow> <flex-shrink> <flex-basis> */
.item {
flex: 0 1 auto; /* default */
flex: 1; /* flex: 1 1 0% — grow, shrink, start at 0 */
flex: auto; /* flex: 1 1 auto — grow, shrink, auto basis */
flex: none; /* flex: 0 0 auto — don't grow or shrink */
flex: 2; /* grow twice as fast as flex: 1 items */
}
/* Classic two-column layout */
.sidebar { flex: 0 0 280px; } /* fixed 280px */
.content { flex: 1; } /* fill remaining space */
align-self
Overrides align-items for a single flex item.
.container {
display: flex;
align-items: center; /* default for all children */
}
.special {
align-self: flex-end; /* this one item aligns to the bottom */
}
.tall {
align-self: stretch; /* this one stretches */
}
order
Controls the visual order of flex items without changing the HTML. Default is 0. Items are ordered from lowest to highest value.
/* Reorder on mobile */
@media (max-width: 600px) {
.sidebar { order: 2; }
.main { order: 1; }
.footer { order: 3; }
}
Use order sparingly — it separates visual order from DOM order, which can hurt keyboard navigation and screen readers.
Real-World Layout Patterns
Navigation Bar
.navbar {
display: flex;
align-items: center;
padding: 0 24px;
height: 64px;
gap: 16px;
}
.navbar-logo { flex: 0 0 auto; margin-right: auto; }
.navbar-links { display: flex; gap: 8px; }
.navbar-cta { flex: 0 0 auto; }
Card Grid with Equal-Height Cards
.card-grid {
display: flex;
flex-wrap: wrap;
gap: 24px;
}
.card {
flex: 1 1 280px; /* grow, shrink, min 280px */
display: flex;
flex-direction: column;
}
.card-body { flex: 1; } /* push footer to bottom */
.card-footer { margin-top: auto; }
Sticky Footer
body {
display: flex;
flex-direction: column;
min-height: 100vh;
}
main { flex: 1; } /* grows to fill available space */
footer { flex-shrink: 0; }
Holy Grail Layout
.page {
display: flex;
flex-direction: column;
min-height: 100vh;
}
.main-content {
display: flex;
flex: 1;
}
.left-sidebar { flex: 0 0 200px; }
.center-column { flex: 1; }
.right-sidebar { flex: 0 0 200px; }
Centering a Modal
.overlay {
position: fixed;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
background: rgba(0, 0, 0, 0.5);
}
.modal {
width: 90%;
max-width: 480px;
background: white;
border-radius: 8px;
padding: 32px;
}
Common Flexbox Pitfalls
Images shrinking unexpectedly
/* Problem: images shrink when container is narrow */
/* Solution: prevent shrinking */
img {
flex-shrink: 0;
}
flex: 1 on a column with text overflow
/* flex: 1 sets flex-basis: 0, which can cause overflow */
.text-col {
flex: 1;
min-width: 0; /* allow the column to shrink below its content size */
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
Not using gap
/* Old approach — fragile with wrapping */
.item + .item { margin-left: 16px; }
/* Modern approach — works with wrapping */
.container {
display: flex;
gap: 16px;
}
Flexbox vs Grid
A common question: when should you use Flexbox versus CSS Grid?
- Use Flexbox for one-dimensional layouts — a row of buttons, a navigation bar, a vertical list of cards, centering a single element.
- Use Grid for two-dimensional layouts — page-level structure, anything with both rows and columns that need to align to each other.
- They complement each other: a Grid-based page layout often has Flexbox inside its cells for aligning content within those cells.
Quick Reference
/* Container */
display: flex | inline-flex
flex-direction: row | row-reverse | column | column-reverse
flex-wrap: nowrap | wrap | wrap-reverse
flex-flow: <direction> <wrap>
justify-content: flex-start | flex-end | center | space-between | space-around | space-evenly
align-items: stretch | flex-start | flex-end | center | baseline
align-content: flex-start | flex-end | center | space-between | space-around | stretch
gap: <row-gap> <column-gap>
/* Items */
flex-grow: <number> (default 0)
flex-shrink: <number> (default 1)
flex-basis: <length> | auto
flex: <grow> <shrink> <basis>
align-self: auto | flex-start | flex-end | center | baseline | stretch
order: <integer> (default 0)
Flexbox becomes second nature once you internalize the axis model. Start with a container, set your direction and wrapping, then control alignment with justify-content and align-items. From there, use item-level properties only when individual items need to deviate from the group behavior.
Free Developer Tools
If you found this article helpful, check out DevToolkit — 40+ free browser-based developer tools with no signup required.
Popular tools: JSON Formatter · Regex Tester · JWT Decoder · Base64 Encoder
🛒 Get the DevToolkit Starter Kit on Gumroad — source code, deployment guide, and customization templates.
Top comments (0)