Learn CSS · Lesson 6 of 7 · 9 min
Flexbox
Flexbox is the tool you reach for when you want a handful of things lined up neatly in one direction: a row of buttons, a navbar, a centered card. You tell a container to be flexible, and its children fall into line and share the space. Once it clicks, half of everyday layout stops being a fight.
The container and its items
Flexbox is always a relationship between one parent and its direct children. The moment you
write display: flex on an element, that element becomes a flex container and
every direct child becomes a flex item. By default the items sit in a single horizontal
row, each only as wide as it needs to be, all aligned along the top.
.toolbar {
display: flex; /* this element is now a flex container */
}
/* every direct child of .toolbar is now a flex item,
laid out in a row, side by side */ That is the whole on-switch. The properties you set on the container (such as
justify-content and align-items, below) control how the group is arranged;
properties you set on an item (such as flex-grow) control how that one item behaves
inside the group. Keeping that container-versus-item split straight is most of the battle.
Two axes: main and cross
Here is the idea that makes everything else make sense. A flex container has two axes. The
main axis is the direction the items flow in; the cross axis runs at a
right angle to it. With the default flex-direction: row, the main axis runs left to right and
the cross axis runs top to bottom.
Flip the direction with flex-direction: column and the items stack vertically instead. The main
axis is now vertical and the cross axis is horizontal. Nothing else about flexbox changes; the same
properties keep working, they just point a new way.
flex-direction: row
flex-direction: column
flex-direction; the cross axis is always at a right angle to it.Why this matters: justify-content always aligns along the main axis, and
align-items always aligns along the cross axis. Learn which axis is which and
you will never have to guess which property to reach for again.
justify-content: spacing along the main axis
justify-content decides how items are positioned and spaced along the main axis.
In a normal row, that means horizontally. The values you will use constantly are
flex-start (the default, items packed to the start), center (packed in the
middle), space-between (first and last item pinned to the edges, equal gaps in between), and
space-around (equal space around every item). Watch the same three items move:
justify-content: flex-start
justify-content: center
justify-content: space-between
justify-content: space-around
justify-content, on the main (horizontal) axis.The difference between space-between and space-around trips people up:
space-between puts no space at the outer edges (items hug the ends), while
space-around gives every item an equal cushion, so there is a half-cushion of space at each
edge. space-between is the classic choice for a header with a logo on the left and a menu on the
right.
align-items: lining up on the cross axis
align-items aligns items along the cross axis, which in a normal row is the
vertical direction. The default is stretch, which makes every item grow to the full height of
the container, handy for equal-height cards. Switch it to center and items of different heights
line up on a shared center line; flex-start pins them to the top, flex-end to the
bottom. Notice the items below are deliberately different heights so the alignment is visible:
align-items: stretch
align-items: center
align-items: flex-start
align-items: flex-end
A quick aside on a near-twin: align-items aligns items on the cross axis, while
align-content (which only kicks in once items wrap onto multiple lines) spaces those whole lines.
For a single row of items, align-items is the one you want.
gap: the clean way to space items
For years people put margins on flex items to separate them, then fought with the unwanted margin on the
first or last child. Forget all that. gap sets even spacing between flex items
in one declaration on the container, with no leftover space at the ends and nothing to clean up.
.toolbar {
display: flex;
gap: 12px; /* 12px between every item, full stop */
} gap: 0
gap: 20px
Unlike vertical margins, gap never collapses (see the
box model lesson for why margins do). It is the modern default for spacing,
and it works identically in grid, so it is worth making a habit.
Flexible sizing and wrapping
The "flex" in flexbox is about letting items grow and shrink to fill the available space. Three properties on each item control this:
flex-grow(default0): how greedily an item expands to soak up leftover space. An item withflex-grow: 1takes all the slack; two items both at1split it evenly.flex-shrink(default1): how willingly an item gives up size when the container is too small. Set it to0to stop an item from shrinking below its natural size.flex-basis(defaultauto): the item's starting size along the main axis, before any growing or shrinking happens.
You will almost always write them together with the flex shorthand, in the order
grow shrink basis. The one you will type most is flex: 1, which means "grow to share
space equally," perfect for columns that should split a row:
.sidebar { flex: 0 0 240px; } /* fixed: no grow, no shrink, 240px */
.content { flex: 1; } /* flexible: take all remaining space */ .sidebar { flex: 0 0 120px } · .content { flex: 1 }
By default a flex container keeps all items on one line, squashing them if it must. Add
flex-wrap: wrap and items that no longer fit drop onto a new line instead of overflowing, the
foundation of responsive rows that reflow on small screens:
.cards {
display: flex;
flex-wrap: wrap; /* items spill onto new lines as needed */
gap: 16px;
} The two patterns you will use forever
Two recipes cover an enormous share of real layout work. Commit them to memory.
1. Perfect centering. Centering a thing both horizontally and vertically used to be a legendary CSS headache. With flexbox it is three lines: turn the parent into a flex container, center on the main axis, center on the cross axis.
.hero {
display: flex;
justify-content: center; /* center on the main axis */
align-items: center; /* center on the cross axis */
min-height: 300px;
} justify-content: center + align-items: center
2. The navbar. A logo pinned to the left, links pinned to the right, vertically aligned in
the middle: that is justify-content: space-between plus align-items: center. This
single pattern is on nearly every site you visit.
.nav {
display: flex;
justify-content: space-between; /* logo left, links right */
align-items: center; /* everything on one line */
} justify-content: space-between + align-items: center
Practice
Two minutes each, and each one locks in a single idea. Use a blank CodePen, your browser's DevTools, or one of our tools to experiment:
- Center a single
divin the dead center of its parent both ways, usingdisplay: flexwithjustify-content: centerandalign-items: center. Then resize the parent and confirm it stays centered. - Build a navbar: a logo on the left and three links on the right, vertically centered. Start from
display: flex, then addjustify-content: space-betweenandalign-items: center. - Make a two-column layout: a fixed
200pxsidebar withflex: 0 0 200pxnext to a content area withflex: 1. Confirm the content stretches to fill whatever space is left.
The mental model to keep
display: flexturns a parent into a container and its direct children into items.- The main axis follows
flex-direction; the cross axis is always at a right angle to it. justify-contentaligns on the main axis;align-itemsaligns on the cross axis.- Use
gapto space items,flex: 1to share space, andflex-wrapto reflow.
That is flexbox: one-dimensional layout that finally behaves. When you need rows and columns at once, full two-dimensional control, that is the job of CSS Grid, the next lesson. Flexbox handles a line; grid handles a plane.