Skip to main content

Flexbox

Flexbox is a one-dimensional layout system. It arranges items in a single row or column and gives you precise control over alignment, spacing, and sizing. Before Flexbox, tasks like centring an element or creating equal-height columns required awkward workarounds. Flexbox makes these trivial.

Flex container and flex items

Flexbox has two roles:

  1. Flex container -- the parent element with display: flex
  2. Flex items -- the direct children of the container
.container {
display: flex;
}
<div class="container">
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
</div>

The moment you set display: flex, the three child divs stop stacking vertically and line up side by side in a row. That is the default behaviour.

Note: Only direct children become flex items. Grandchildren and deeper descendants are not affected by the flex container.

flex-direction

Controls the main axis -- the direction items flow:

ValueDirection
row (default)Left to right (horizontal)
row-reverseRight to left
columnTop to bottom (vertical)
column-reverseBottom to top
.horizontal {
display: flex;
flex-direction: row;
}

.vertical {
display: flex;
flex-direction: column;
}

The main axis is the direction items flow. The cross axis is perpendicular to it. For flex-direction: row, the main axis is horizontal and the cross axis is vertical. For flex-direction: column, they swap.

flex-wrap

By default, flex items try to fit on a single line, shrinking if necessary. flex-wrap lets items wrap to new lines:

.container {
display: flex;
flex-wrap: wrap;
}
ValueBehaviour
nowrap (default)All items on one line (may shrink)
wrapItems wrap to the next line
wrap-reverseItems wrap upward
.card-grid {
display: flex;
flex-wrap: wrap;
gap: 16px;
}

.card-grid .card {
width: 250px;
}

Cards that do not fit on one line wrap to the next row.

flex-flow shorthand

Combines flex-direction and flex-wrap:

.container {
flex-flow: row wrap;
}

Alignment

Flexbox has four alignment properties. Two control the main axis, two control the cross axis.

justify-content (main axis)

Distributes space along the main axis:

ValueBehaviour
flex-startPack items at the start (default)
flex-endPack items at the end
centerCentre items
space-betweenEqual space between items, no space at edges
space-aroundEqual space around each item (half-space at edges)
space-evenlyTruly equal space between and around items
.nav {
display: flex;
justify-content: space-between;
padding: 16px;
}

align-items (cross axis)

Aligns items along the cross axis:

ValueBehaviour
stretchItems stretch to fill the container (default)
flex-startAlign items to the start of the cross axis
flex-endAlign items to the end
centerCentre items on the cross axis
baselineAlign items by their text baseline
.container {
display: flex;
align-items: center;
height: 200px;
}

align-self (cross axis, per item)

Overrides align-items for a single flex item:

.container {
display: flex;
align-items: flex-start;
}

.special {
align-self: flex-end;
}

align-content (multi-line cross axis)

Controls spacing between wrapped lines. Only applies when flex-wrap: wrap is set and there are multiple lines:

.container {
display: flex;
flex-wrap: wrap;
align-content: space-between;
height: 400px;
}

Same values as justify-content: flex-start, flex-end, center, space-between, space-around, space-evenly, stretch.

The gap property

gap adds space between flex items without adding space at the edges:

.container {
display: flex;
gap: 16px;
}

You can set row and column gaps separately:

.container {
display: flex;
flex-wrap: wrap;
row-gap: 24px;
column-gap: 16px;
}

Tip: Before gap existed for flexbox, developers used margins on items and negative margins on containers. That hack is no longer necessary. gap is supported in all modern browsers.

Flex item sizing

Three properties control how flex items grow and shrink.

flex-grow

Determines how much an item grows to fill available space. The default is 0 (do not grow).

.item {
flex-grow: 1;
}

If all items have flex-grow: 1, they share extra space equally. If one item has flex-grow: 2, it gets twice as much extra space as items with flex-grow: 1.

flex-shrink

Determines how much an item shrinks when there is not enough space. The default is 1 (shrink proportionally).

.sidebar {
flex-shrink: 0;
}

Setting flex-shrink: 0 prevents an item from shrinking below its natural size. This is useful for fixed-width sidebars.

flex-basis

Sets the initial size of an item before growing or shrinking. It replaces width (for rows) or height (for columns) in a flex context:

.sidebar {
flex-basis: 250px;
flex-shrink: 0;
}

.main {
flex-basis: 0;
flex-grow: 1;
}

The flex shorthand

Combines all three into one declaration:

/* flex: grow shrink basis */
.item {
flex: 1 1 0;
}

Common shorthands:

ShorthandEquivalentMeaning
flex: 1flex: 1 1 0Grow and shrink equally
flex: autoflex: 1 1 autoGrow/shrink from content size
flex: noneflex: 0 0 autoFixed size, no grow, no shrink
flex: 0 0 200pxflex: 0 0 200pxFixed 200px, never grows/shrinks

Tip: Use the flex shorthand instead of setting flex-grow, flex-shrink, and flex-basis separately. It is more readable and sets sensible defaults.

order

By default, flex items appear in their HTML source order. The order property overrides this:

.first {
order: -1;
}

.last {
order: 1;
}

Lower values appear first. The default is 0. Use order sparingly -- it can make the visual order inconsistent with the DOM order, which hurts accessibility.

Common Flexbox patterns

Centring anything

The most famous use case. Centre an element both horizontally and vertically:

.center-wrapper {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px 24px;
background-color: #1a1a2e;
}

.navbar .logo {
font-size: 1.5rem;
font-weight: bold;
color: white;
}

.navbar .links {
display: flex;
gap: 20px;
}

.navbar .links a {
color: white;
text-decoration: none;
}

Card row

.card-row {
display: flex;
flex-wrap: wrap;
gap: 20px;
}

.card-row .card {
flex: 1 1 280px;
padding: 24px;
border: 1px solid #ddd;
border-radius: 8px;
background-color: white;
}

flex: 1 1 280px means: start at 280px, grow to fill space, wrap when there is not enough room. This creates a responsive card layout without media queries.

Sidebar + main content

.layout {
display: flex;
min-height: 100vh;
}

.sidebar {
flex: 0 0 260px;
padding: 24px;
background-color: #f5f5f5;
}

.main {
flex: 1;
padding: 24px;
}

The sidebar stays at 260px. The main content takes up all remaining space.

A common problem: make the footer stick to the bottom of the page even when content is short.

body {
display: flex;
flex-direction: column;
min-height: 100vh;
margin: 0;
}

main {
flex: 1;
}

footer {
padding: 16px;
background-color: #333;
color: white;
}

flex: 1 on main makes it grow to fill all available vertical space, pushing the footer down.

Flexbox vs older techniques

TaskOld wayFlexbox way
Centre verticallytransform: translateY(-50%)align-items: center
Equal-height colsdisplay: table-cell or JSItems stretch by default
Space between itemsMargins + negative marginsgap
Reorder itemsChange HTML or use floatsorder
Sticky footercalc(100vh - header - footer)flex: 1 on main

What you learned

  • Set display: flex on a container to create a flex context
  • flex-direction controls the main axis (row or column)
  • justify-content aligns items along the main axis; align-items along the cross axis
  • gap adds space between items without edge spacing
  • flex-grow, flex-shrink, and flex-basis (or the flex shorthand) control item sizing
  • Common patterns: centring, nav bars, card grids, sidebars, and sticky footers

Next step

Flexbox handles one-dimensional layouts. The next chapter introduces CSS Grid -- a two-dimensional layout system for rows and columns simultaneously.