Flexbox
The Flexible Box Layout module provides an efficient way to lay out, align, and distribute space among items in a container — even when their size is unknown or dynamic.
Display Flex
Setting display: flex on a container makes it a flex container, and its direct children become flex items. This is the foundation of all flexbox layouts.
.container { display: flex; /* block-level flex container */ } .container-inline { display: inline-flex; /* inline-level flex container */ }
Without flex (normal block flow):
With display: flex:
Flexbox works along two axes: the main axis (defined by flex-direction) and the cross axis (perpendicular to it). By default, the main axis runs left-to-right and the cross axis runs top-to-bottom.
Flex Direction
The flex-direction property defines the main axis direction — the direction flex items are placed in the container.
.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 */ }
flex-direction: row (default)
flex-direction: row-reverse
flex-direction: column
flex-direction: column-reverse
Flex Wrap
By default, flex items try to fit onto one line. flex-wrap controls whether items are forced onto a single line or can wrap onto multiple lines.
.container { display: flex; flex-wrap: nowrap; /* default — single line, items may shrink */ flex-wrap: wrap; /* items wrap to new lines */ flex-wrap: wrap-reverse; /* items wrap in reverse order */ } /* Shorthand: flex-flow combines direction + wrap */ .container { flex-flow: row wrap; }
Resize the browser to see items wrap to new lines.
Justify Content
Distributes space along the main axis. This is the most commonly used alignment property in flexbox.
.container { display: flex; 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; /* equal space between items */ justify-content: space-around; /* equal space around items */ justify-content: space-evenly; /* truly equal spacing */ }
justify-content: flex-start
justify-content: flex-end
justify-content: center
justify-content: space-between
justify-content: space-around
justify-content: space-evenly
space-between: First item at start, last at end, equal space between. space-around: Equal space around each item (edges get half-size space). space-evenly: Truly equal space everywhere, including edges.
Align Items
Aligns items along the cross axis (perpendicular to flex-direction). Works on a single line of items.
.container { display: flex; align-items: stretch; /* default — fill the container height */ align-items: flex-start; /* align to top */ align-items: flex-end; /* align to bottom */ align-items: center; /* center vertically */ align-items: baseline; /* align text baselines */ }
align-items: stretch (default)
text
align-items: flex-start
text
align-items: flex-end
text
align-items: center
text
align-items: baseline
Align Content
Aligns multiple lines of flex items along the cross axis. Only works when flex-wrap: wrap is set and there are multiple lines.
.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; /* default — lines stretch */ }
align-items aligns items within a single flex line. align-content aligns the lines themselves when there is extra space on the cross axis. align-content has no effect on single-line flex containers.
Gap
The gap property sets spacing between flex items without adding margins. Clean, simple, and predictable.
.container { display: flex; gap: 1rem; /* both row and column gap */ row-gap: 1rem; /* gap between rows */ column-gap: 0.5rem; /* gap between columns */ gap: 1rem 0.5rem; /* row-gap column-gap */ }
Unlike margins, gap only creates space between items, never on the outer edges. This eliminates the need for negative margin hacks on the container.
Flex Grow
flex-grow defines how much a flex item should grow relative to other items when there is extra space on the main axis. Default is 0 (do not grow).
.item { flex-grow: 0; /* default — don't grow */ flex-grow: 1; /* take up available space */ flex-grow: 2; /* grow twice as much as flex-grow:1 */ }
All items start with equal base size, but grow at different rates:
All flex-grow: 1 (equal distribution)
Ratio 1 : 2 : 1
Ratio 1 : 3 : 1
Flex Shrink
flex-shrink defines how much a flex item should shrink relative to other items when there is not enough space. Default is 1.
.item { flex-shrink: 1; /* default — will shrink */ flex-shrink: 0; /* won't shrink — maintains size */ flex-shrink: 2; /* shrinks twice as fast */ }
Flex Basis
flex-basis sets the initial main size of a flex item before growing or shrinking. Think of it as the "ideal" size.
.item { flex-basis: auto; /* default — use width/height or content */ flex-basis: 200px; /* fixed starting size */ flex-basis: 30%; /* percentage of container */ flex-basis: 0; /* ignore content size, distribute all space */ }
When both flex-basis (not auto) and width are set, flex-basis wins. Use flex-basis for flex layouts — it's the semantically correct property and works regardless of flex-direction.
Flex Shorthand
The flex shorthand combines flex-grow, flex-shrink, and flex-basis. Always prefer the shorthand — it sets better defaults.
.item { /* flex: grow shrink basis */ flex: 0 1 auto; /* default (when not using shorthand) */ flex: 1; /* flex: 1 1 0 — grow equally, ignore content size */ flex: auto; /* flex: 1 1 auto — grow equally, respect content */ flex: none; /* flex: 0 0 auto — rigid, no grow, no shrink */ flex: 0 0 200px; /* fixed 200px, no flexibility */ }
flex: 1 (equal sizing, ignores content)
flex: auto (equal sizing, respects content)
flex: none (rigid, content-sized)
flex: 0 0 200px (fixed 200px)
flex:1 sets flex-basis:0, so items size equally regardless of content. flex:auto sets flex-basis:auto, so items with more content get more space. For equal columns, use flex:1.
Align Self
Overrides align-items for a single flex item. Allows individual items to position themselves differently on the cross axis.
.item { align-self: auto; /* default — follow align-items */ align-self: flex-start; /* top */ align-self: flex-end; /* bottom */ align-self: center; /* center */ align-self: stretch; /* fill */ align-self: baseline; /* text baseline */ }
(flex-start)
center
flex-end
stretch
Order
The order property controls the visual order of flex items without changing the HTML source order. Default is 0.
.item-a { order: 3; } /* appears last */ .item-b { order: 1; } /* appears first */ .item-c { order: 2; } /* appears second */
HTML order: A, B, C, D. Visual order changed via CSS order property:
Displayed: B, D, A, C
order only changes visual rendering, not tab order or screen reader order. Users navigating with a keyboard or assistive technology will encounter items in their DOM order. Use with caution.
Perfect Centering
The classic CSS centering problem, solved elegantly with flexbox in just 3 lines.
/* The holy grail of centering */ .center-perfect { display: flex; justify-content: center; /* horizontal center */ align-items: center; /* vertical center */ } /* Alternative: place-content shorthand */ .center-alt { display: flex; place-content: center; /* centers both axes */ } /* Another way: margin auto on the child */ .center-container { display: flex; } .center-container > .child { margin: auto; /* centers in both directions */ }
Real-World Patterns
Common UI layouts built with flexbox. Copy these patterns for your projects.
Navbar
.navbar { display: flex; justify-content: space-between; align-items: center; padding: 0.75rem 1.5rem; } .navbar-links { display: flex; gap: 1.5rem; align-items: center; }
Card Row
.card-row { display: flex; gap: 1.5rem; flex-wrap: wrap; } .card { flex: 1 1 300px; /* grow, shrink, min 300px */ }
This card will grow and shrink. Try resizing the browser window.
Equal sizing with flex:1, wrapping when items reach their minimum width.
Responsive without a single media query.
Media Object
.media { display: flex; gap: 1rem; align-items: flex-start; } .media-image { flex-shrink: 0; /* don't shrink the image */ width: 64px; height: 64px; border-radius: 50%; } .media-body { flex: 1; /* take remaining space */ }
This is the classic media object pattern. The avatar never shrinks thanks to flex-shrink:0, and the text takes all remaining space with flex:1.
Input Group
.input-group { display: flex; } .input-group input { flex: 1; /* input takes available space */ } .input-group button { flex-shrink: 0; /* button stays fixed */ }
Gotchas
Flex items have min-width: auto by default, which means they won't shrink smaller than their content. This causes overflow with long text or code. Fix: add min-width: 0 or overflow: hidden to the flex item.
/* Problem: text overflows flex container */ .flex-item { flex: 1; /* Long text or pre elements will overflow! */ } /* Solution */ .flex-item { flex: 1; min-width: 0; /* allow shrinking below content size */ }
In flexbox, margin: auto absorbs extra space. A common trick: margin-left: auto on the last nav item pushes it to the right. This is more powerful than it seems — it works on both axes.
/* Push the last item to the right */ .nav-item:last-child { margin-left: auto; /* absorbs all extra space */ }
Login button pushed to the right with margin-left: auto
When using flex-direction: column, the main axis becomes vertical. This means justify-content works vertically and align-items works horizontally. The container also needs a defined height for justify-content to have visible effect.
Pro Tips
Wrap your page in a flex container with flex-direction: column and min-height: 100vh. Set flex: 1 on the main content area — the footer automatically sticks to the bottom.
/* Sticky footer pattern */ body { display: flex; flex-direction: column; min-height: 100vh; } main { flex: 1; /* pushes footer down */ }
Flex items in a row automatically get equal heights (because of align-items: stretch). To make the card content push the button to the bottom, make the card itself a flex column with flex-direction: column, and use margin-top: auto on the button.
.card-row { display: flex; gap: 1rem; } .card { flex: 1; display: flex; flex-direction: column; } .card-button { margin-top: auto; /* pushes to bottom of card */ }
Use Flexbox for one-dimensional layouts (a single row or column) and for content-driven sizing. Use Grid for two-dimensional layouts (rows AND columns) and for layout-driven sizing. They work beautifully together — use grid for the page layout and flex for components inside it.
When debugging flex layouts, add outline: 1px solid red to flex items (not border — outlines don't affect layout). Or use browser DevTools which now have excellent flexbox overlays.