What Is Flexbox?
Flexbox (Flexible Box Layout) is a one-dimensional CSS layout model designed to distribute space and align items inside a container — even when their sizes are unknown or dynamic. Before flexbox, developers relied on floats, inline-block hacks, and tables for layout. Flexbox replaced all of that with a clean, predictable system.
.container {
display: flex;
}
That single line turns the container into a flex container and its direct children into flex items. Nothing else changes — the children simply gain flex superpowers.
The Two Axes
Everything in flexbox revolves around two axes:
Main Axis (flex-direction: row)
-------------------------------------------->
| [Item 1] [Item 2] [Item 3] [Item 4] |
<--------------------------------------------
Cross Axis (perpendicular)
|
| [Item 1] [Item 2] [Item 3]
|
v
- Main axis — the direction items flow. Controlled by
flex-direction. - Cross axis — perpendicular to the main axis. Always 90 degrees from main.
When flex-direction is row, main axis is horizontal. When column, main axis is vertical. This distinction matters for every alignment property.
flex-direction: row flex-direction: column
Main ------> Main
[A] [B] [C] |
^ v
| [A]
Cross [B]
[C]
Cross -->
Flex Container Properties
These properties go on the parent element — the flex container.
display: flex vs display: inline-flex
/* Block-level flex container — takes full width */
.container {
display: flex;
}
/* Inline-level flex container — shrinks to content width */
.container-inline {
display: inline-flex;
}
Use inline-flex when you need the container to sit alongside other inline elements. In practice, display: flex covers 95% of use cases.
flex-direction
Controls the main axis direction.
.container {
display: flex;
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 */
}
Common mistake: forgetting that justify-content and align-items swap their visual effect when you switch from row to column. justify-content: center centers horizontally in row mode but vertically in column mode.
justify-content
Aligns items along the main axis.
.container {
display: flex;
justify-content: flex-start; /* packed to start (default) */
justify-content: flex-end; /* packed to end */
justify-content: center; /* centered */
justify-content: space-between; /* equal space between items */
justify-content: space-around; /* equal space around each item */
justify-content: space-evenly; /* truly even spacing everywhere */
}
Visual comparison:
flex-start: [A][B][C]...............
flex-end: ...............[A][B][C]
center: .......[A][B][C].......
space-between: [A]......[B]......[C]
space-around: ..[A]....[B]....[C]..
space-evenly: ...[A]...[B]...[C]...
The difference between space-around and space-evenly:
space-aroundgives each item equal margin on both sides. Edge items have half the gap vs interior items.space-evenlymakes every gap identical, including edges.
align-items
Aligns items along the cross axis.
.container {
display: flex;
align-items: stretch; /* default: fill container height */
align-items: flex-start; /* top-aligned (in row mode) */
align-items: flex-end; /* bottom-aligned */
align-items: center; /* vertically centered */
align-items: baseline; /* aligned by text baseline */
}
stretch: |AAAA|BBBBBB|CCC | (all same height)
flex-start: |AA |BBBB |C |
flex-end: | AA| BBBB| C|
center: | AA | BB | C |
baseline: |Aa |Bb |Cc | (text baselines align)
baseline is underused. When you have items with different font sizes and want their text to line up, baseline is the answer.
align-content
Controls spacing between wrapped lines (only works with flex-wrap: wrap).
.container {
display: flex;
flex-wrap: wrap;
align-content: flex-start; /* lines packed to top */
align-content: flex-end; /* lines packed to bottom */
align-content: center; /* lines centered */
align-content: space-between; /* equal space between lines */
align-content: space-around; /* equal space around lines */
align-content: stretch; /* lines stretch to fill (default) */
}
Important: align-content has no effect on single-line flex containers. You need flex-wrap: wrap AND multiple lines for it to do anything.
flex-wrap
Controls whether items wrap to new lines.
.container {
flex-wrap: nowrap; /* default: single line, items may shrink */
flex-wrap: wrap; /* wrap to new lines below */
flex-wrap: wrap-reverse; /* wrap to new lines above */
}
nowrap: [A][B][C][D][E][F] (all squeezed into one line)
wrap: [A][B][C][D]
[E][F]
wrap-reverse: [E][F]
[A][B][C][D]
flex-flow Shorthand
Combines flex-direction and flex-wrap:
.container {
flex-flow: row nowrap; /* default */
flex-flow: column wrap; /* vertical with wrapping */
flex-flow: row-reverse wrap; /* reversed horizontal with wrapping */
}
gap
Adds spacing between flex items. This is the modern replacement for margin hacks.
.container {
display: flex;
gap: 16px; /* equal row and column gap */
row-gap: 16px; /* gap between rows (when wrapping) */
column-gap: 8px; /* gap between columns */
}
Before gap, developers used margins with negative margins on the container, or :last-child selectors to remove trailing margins. gap solves this cleanly.
/* OLD approach (avoid) */
.item { margin-right: 16px; }
.item:last-child { margin-right: 0; }
/* MODERN approach */
.container { display: flex; gap: 16px; }
Browser support for gap in flexbox is excellent — supported in all modern browsers since 2021. Safe to use in production.
Flex Item Properties
These properties go on the children — the flex items.
flex-grow
How much an item should grow relative to its siblings when there is extra space.
.item-a { flex-grow: 0; } /* default: don't grow */
.item-b { flex-grow: 1; } /* take remaining space */
.item-c { flex-grow: 2; } /* take 2x as much remaining space as item-b */
Container: [........................................]
400px total, items need 200px
flex-grow: 0, 1, 2
[AAA (fixed)][BBBBBBB (67px extra)][CCCCCCCCCCCCCC (133px extra)]
The 200px of remaining space is divided:
- A gets 0 shares (stays at content width)
- B gets 1/3 = 67px extra
- C gets 2/3 = 133px extra
flex-shrink
How much an item should shrink when the container is too small.
.item { flex-shrink: 1; } /* default: shrink proportionally */
.item { flex-shrink: 0; } /* never shrink — content may overflow */
.item { flex-shrink: 3; } /* shrink 3x as aggressively */
flex-shrink: 0 is useful for fixed-size elements like icons or buttons that should never compress.
flex-basis
The initial size of an item before flex-grow or flex-shrink kicks in.
.item { flex-basis: auto; } /* default: use width/height or content */
.item { flex-basis: 200px; } /* start at 200px, then grow/shrink */
.item { flex-basis: 50%; } /* start at 50% of container */
.item { flex-basis: 0; } /* ignore content size completely */
How flex-basis differs from width:
flex-basisis a suggestion — flexbox may override it via grow/shrink.widthis a constraint but flex-basis takes priority when both are set.- In
flex-direction: column,flex-basisacts likeheight.
The flex Shorthand
The flex shorthand is the recommended way to set grow, shrink, and basis together.
.item { flex: initial; } /* 0 1 auto — don't grow, can shrink */
.item { flex: auto; } /* 1 1 auto — grow and shrink freely */
.item { flex: none; } /* 0 0 auto — rigid, no flex at all */
.item { flex: 1; } /* 1 1 0% — grow equally, ignore content */
.item { flex: 2; } /* 2 1 0% — grow 2x, ignore content */
.item { flex: 0 1 auto; } /* explicit default values */
.item { flex: 2 0 200px; } /* grow 2x, don't shrink, start at 200px */
Important gotcha: flex: 1 sets flex-basis: 0%, not auto. This means content size is ignored and all items get truly equal widths. If you want items to respect their content size while still growing, use flex: 1 1 auto.
/* Equal widths regardless of content */
.equal-items { flex: 1; } /* basis: 0% */
/* Proportional to content, but fill remaining space */
.proportional-items { flex: 1 1 auto; } /* basis: auto */
align-self
Override the container's align-items for a single item.
.container {
display: flex;
align-items: flex-start;
}
.special-item {
align-self: flex-end; /* this one goes to the bottom */
}
.centered-item {
align-self: center; /* this one centers vertically */
}
Possible values: auto (inherit from container), flex-start, flex-end, center, baseline, stretch.
order
Change visual order without modifying HTML. Default is 0.
.sidebar { order: 1; } /* visually first */
.main { order: 2; } /* visually second */
.aside { order: 3; } /* visually third */
Accessibility warning: order changes only the visual order. Screen readers and keyboard navigation still follow DOM order. Use sparingly and only when the visual reorder doesn't break the logical reading flow.
/* Responsive reordering — mobile shows main content first */
@media (max-width: 768px) {
.sidebar { order: 2; }
.main { order: 1; }
}
Real-World Layout Patterns
1. Perfect Centering
The most common flexbox use case. Center anything horizontally and vertically.
.center-everything {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
For centering a single child, you can also use margin: auto on the item:
.container {
display: flex;
min-height: 100vh;
}
.centered-child {
margin: auto; /* centers in both axes */
}
2. Navigation Bar
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 1rem;
height: 60px;
}
.nav-left {
display: flex;
align-items: center;
gap: 1rem;
}
.nav-right {
display: flex;
align-items: center;
gap: 0.5rem;
}
[Logo Home About] [Search Login]
|--- nav-left -----| |-- nav-right -|
|--------------- space-between -----------------------|
3. Responsive Card Layout
.card-grid {
display: flex;
flex-wrap: wrap;
gap: 1rem;
}
.card {
flex: 1 1 300px; /* grow, shrink, min 300px */
max-width: 100%; /* prevent overflow on mobile */
}
This pattern creates cards that are at least 300px wide, grow to fill available space, and wrap to new rows when the container gets narrow. No media queries needed.
4. Sticky Footer
Page footer that stays at the bottom even with short content.
.page {
display: flex;
flex-direction: column;
min-height: 100vh;
}
.header { /* natural height */ }
.content { flex: 1; } /* grows to push footer down */
.footer { /* natural height, always at bottom */ }
+------------------+
| Header |
+------------------+
| |
| Content | <- flex: 1 (fills remaining space)
| |
| |
+------------------+
| Footer | <- always at bottom
+------------------+
5. Input Group (Search Bar)
.input-group {
display: flex;
max-width: 500px;
}
.input-group input {
flex: 1; /* takes all available space */
min-width: 0; /* allows shrinking below content size */
padding: 0.5rem;
}
.input-group button {
flex-shrink: 0; /* button never shrinks */
padding: 0.5rem 1rem;
}
The min-width: 0 on the input is critical. By default, flex items have min-width: auto, which prevents them from shrinking below their content size. For inputs and elements with text, this can cause overflow.
6. Sidebar Layout
.app-layout {
display: flex;
min-height: 100vh;
}
.sidebar {
flex: 0 0 250px; /* fixed 250px, no grow, no shrink */
}
.main-content {
flex: 1; /* fills remaining space */
min-width: 0; /* prevents overflow from wide content */
}
/* Collapse sidebar on mobile */
@media (max-width: 768px) {
.app-layout {
flex-direction: column;
}
.sidebar {
flex-basis: auto; /* natural height in column mode */
}
}
7. Equal Height Cards
One of flexbox's best features — child elements automatically match the tallest sibling's height.
.card-row {
display: flex;
gap: 1rem;
}
.card {
flex: 1;
display: flex;
flex-direction: column;
}
.card-body {
flex: 1; /* pushes footer to bottom of card */
}
.card-footer {
/* always aligned at bottom across all cards */
}
+----------+ +----------+ +----------+
| Title | | Title | | Title |
| | | | | |
| Body | | Body | | Body |
| (long) | | (short) | | (medium) |
| | | flex:1 | | |
| | | fills | | |
+----------+ +----------+ +----------+
| Footer | | Footer | | Footer |
+----------+ +----------+ +----------+
8. Media Object
A classic pattern: image on the left, text on the right.
.media {
display: flex;
gap: 1rem;
align-items: flex-start;
}
.media-image {
flex-shrink: 0; /* image never compresses */
width: 80px;
height: 80px;
}
.media-body {
flex: 1;
min-width: 0; /* allows text truncation */
}
.media-body h3 {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
9. Holy Grail Layout
The classic three-column layout with header and footer.
.page {
display: flex;
flex-direction: column;
min-height: 100vh;
}
.page-body {
display: flex;
flex: 1;
}
.left-sidebar { flex: 0 0 200px; }
.main-content { flex: 1; min-width: 0; }
.right-sidebar { flex: 0 0 200px; }
@media (max-width: 768px) {
.page-body { flex-direction: column; }
.left-sidebar,
.right-sidebar { flex-basis: auto; }
}
10. Masonry-Like Columns
While not true masonry, flexbox can create a column-based layout.
.masonry {
display: flex;
flex-wrap: wrap;
gap: 1rem;
}
.masonry-column {
flex: 1 1 300px;
display: flex;
flex-direction: column;
gap: 1rem;
}
Responsive Flexbox Patterns
Mobile-First Navigation
.nav {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
@media (min-width: 768px) {
.nav {
flex-direction: row;
justify-content: space-between;
align-items: center;
}
}
Responsive Form
.form-row {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
@media (min-width: 640px) {
.form-row {
flex-direction: row;
gap: 1rem;
}
.form-row label {
flex: 0 0 120px;
}
.form-row input {
flex: 1;
}
}
Responsive Feature Grid
.features {
display: flex;
flex-wrap: wrap;
gap: 2rem;
}
.feature {
flex: 1 1 250px; /* responsive without media queries */
}
/* Optional: limit to 3 columns max */
.feature {
flex: 1 1 calc(33.333% - 2rem);
max-width: calc(33.333% - 2rem);
}
@media (max-width: 768px) {
.feature {
flex: 1 1 100%;
max-width: 100%;
}
}
Common Flexbox Mistakes
Mistake 1: Forgetting min-width: 0
Flex items default to min-width: auto, which prevents them from shrinking below their content size. This causes overflow with long text or large images.
/* BUG: long text overflows container */
.item {
flex: 1;
}
/* FIX: allow shrinking below content size */
.item {
flex: 1;
min-width: 0;
}
Mistake 2: Using width Instead of flex-basis
/* Works but less flexible */
.item { width: 200px; }
/* Preferred in flex context */
.item { flex: 0 0 200px; }
Mistake 3: Nesting Too Many Flex Containers
Every display: flex creates a new formatting context. Deep nesting can make layouts fragile and hard to debug.
/* Overly nested — hard to maintain */
.level-1 { display: flex; }
.level-2 { display: flex; }
.level-3 { display: flex; }
.level-4 { display: flex; }
/* Better: flatten structure or use Grid for 2D layouts */
Mistake 4: Ignoring flex-shrink on Fixed Elements
/* BUG: icon shrinks when space is tight */
.icon { width: 24px; }
/* FIX: prevent shrinking */
.icon {
width: 24px;
flex-shrink: 0;
}
Mistake 5: Relying on order for Accessibility
/* Visual order: C, A, B */
.item-a { order: 2; }
.item-b { order: 3; }
.item-c { order: 1; }
/* Screen reader still reads: A, B, C (DOM order) */
/* Keyboard tab order: A, B, C (DOM order) */
Always ensure the DOM order makes logical sense. Use order only for minor visual adjustments.
Mistake 6: Using Flexbox When Grid Is Better
Flexbox is one-dimensional. If you need items to align in both rows AND columns, use CSS Grid.
/* Awkward with flexbox — items don't align in columns */
.grid-attempt {
display: flex;
flex-wrap: wrap;
}
/* Clean with grid */
.proper-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
}
Browser Support & Compatibility
Flexbox has excellent browser support. All modern browsers have fully supported it since 2015.
| Feature | Chrome | Firefox | Safari | Edge |
|---|---|---|---|---|
| Basic flexbox | 29+ | 28+ | 9+ | 12+ |
| flex-wrap | 29+ | 28+ | 9+ | 12+ |
| gap in flexbox | 84+ | 63+ | 14.1+ | 84+ |
The only concern is gap in flexbox contexts — older Safari versions (pre-14.1) don't support it. If supporting older browsers:
/* Fallback for older browsers */
.container {
display: flex;
flex-wrap: wrap;
margin: -0.5rem;
}
.item {
margin: 0.5rem;
}
/* Modern browsers */
@supports (gap: 1rem) {
.container {
gap: 1rem;
margin: 0;
}
.item {
margin: 0;
}
}
Debugging Flexbox
Browser DevTools
Every modern browser has flexbox debugging built in:
- Chrome/Edge: Inspect element, look for the
flexbadge. Click it to see overlay. - Firefox: Best flexbox inspector. Shows main/cross axis, item sizes, free space.
- Safari: Inspect element, Layout tab shows flex information.
Common Debug Checklist
1. Is the container actually display: flex?
→ Check computed styles
2. Are items overflowing?
→ Check min-width: auto (default)
→ Add min-width: 0 to flex items
3. Items not growing?
→ Check flex-grow (default is 0)
→ Check if max-width is constraining
4. Items not wrapping?
→ Check flex-wrap (default is nowrap)
→ Check if container has a fixed width
5. Alignment not working?
→ Check which axis you're targeting
→ justify-content = main axis
→ align-items = cross axis
→ Verify flex-direction (it changes which axis is which)
Flexbox Interview Questions
Q1: What is the difference between justify-content and align-items?
justify-content aligns items along the main axis (horizontal by default). align-items aligns items along the cross axis (vertical by default). When flex-direction changes, so do the axes.
Q2: What does flex: 1 actually mean?
flex: 1 is shorthand for flex-grow: 1, flex-shrink: 1, flex-basis: 0%. It means the item will grow to fill available space, can shrink, and its initial size is 0 (ignoring content width). This makes all flex: 1 items equal width.
Q3: How do you create equal-width columns with flexbox?
.container { display: flex; }
.column { flex: 1; }
Each column gets the same width regardless of content, because flex: 1 sets flex-basis: 0%.
Q4: What is min-width: auto and why does it matter?
By default, flex items have min-width: auto, which means they refuse to shrink below their content size. This often causes unexpected overflow. Setting min-width: 0 allows the item to shrink below its content size.
Q5: Can you change the visual order of flex items without changing HTML?
Yes, using the order property. Default is 0. Lower values appear first. However, this only changes visual order — screen readers and keyboard navigation still follow DOM order.
Q6: When should you use flexbox vs CSS Grid?
Use flexbox for one-dimensional layouts — a single row or column of items. Use Grid for two-dimensional layouts where items need to align in both rows and columns simultaneously. They can also be combined.
Q7: What is the difference between flex-basis and width?
flex-basis defines the initial size of a flex item before grow/shrink is applied. width is a general CSS property. In a flex context, flex-basis takes priority over width. In flex-direction: column, flex-basis acts as height.
Q8: How does gap differ from margins in flexbox?
gap creates space between items only — not on the edges. Margins add space around each item individually, including edges. gap is cleaner and doesn't require :first-child / :last-child overrides.
Advanced Techniques
Fluid Widths with calc()
/* Three columns with gap accounted for */
.item {
flex: 0 0 calc(33.333% - 1rem);
}
Flex and Auto Margins
margin: auto in flexbox absorbs all available space in that direction.
.nav {
display: flex;
align-items: center;
}
/* Push everything after this item to the right */
.nav-item-push {
margin-left: auto;
}
[Home] [About] [Blog] [Login] [Signup]
^
margin-left: auto pushes these right
Nested Flex Containers
.outer {
display: flex;
gap: 1rem;
}
.sidebar {
flex: 0 0 250px;
}
.main {
flex: 1;
display: flex; /* nested flex */
flex-direction: column;
gap: 1rem;
}
.main-header { /* natural height */ }
.main-body { flex: 1; }
.main-footer { /* natural height */ }
Truncating Text in Flex Items
.flex-item {
flex: 1;
min-width: 0; /* required for truncation to work */
}
.flex-item span {
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
Without min-width: 0 on the flex item, the text will overflow instead of truncating.
Performance Notes
Flexbox layout is fast. The browser calculates flex sizing in a single pass for simple layouts. Performance tips:
- Avoid deeply nested flex containers — each level adds a layout calculation.
- Use
will-change: transformonly when animating flex items — not as a default. flex-wrap: wrapwith many items is slightly more expensive thannowrapbecause the browser must calculate line breaks.- Avoid mixing percentage and pixel flex-basis values in the same container — it complicates the layout algorithm.
In real-world applications, flexbox performance is rarely a bottleneck. Focus on correct layout first, optimize only if you measure a problem.
Quick Reference Table
| Property | Applies To | Values |
|---|---|---|
| display | container | flex, inline-flex |
| flex-direction | container | row, row-reverse, column, column-reverse |
| flex-wrap | container | nowrap, wrap, wrap-reverse |
| justify-content | container | flex-start, flex-end, center, space-between, space-around, space-evenly |
| align-items | container | stretch, flex-start, flex-end, center, baseline |
| align-content | container | stretch, flex-start, flex-end, center, space-between, space-around |
| gap | container | length (e.g., 16px, 1rem) |
| flex-grow | item | number (default 0) |
| flex-shrink | item | number (default 1) |
| flex-basis | item | auto, length, percentage (default auto) |
| flex | item | shorthand for grow shrink basis |
| align-self | item | auto, flex-start, flex-end, center, baseline, stretch |
| order | item | integer (default 0) |
Key Takeaways
display: flexcreates a flex container; direct children become flex items.- Main axis is controlled by
flex-direction, aligned withjustify-content. - Cross axis is perpendicular, aligned with
align-items(container) oralign-self(item). - Use
flex: 1for equal-width items that fill available space. - Use
gapinstead of margin hacks for spacing between items. - Always add
min-width: 0on flex items that contain text or wide content. - Use
flex-shrink: 0on elements that should never compress (icons, buttons). - Flexbox is ideal for one-dimensional layouts (rows or columns).
- For two-dimensional layouts (rows AND columns), use CSS Grid instead.
orderchanges visual order only — DOM order still controls screen readers and keyboard.- When debugging, check the axis direction first —
flex-directionchanges everything.