Learn CSS · Lesson 6 of 11 · 10 min

Flexbox

Widely availablesince Mar 2018 Widely availablesince Oct 2023

Flexbox lays things out along one line: a nav bar, a row of buttons, a label beside an input. It has eleven properties worth knowing, and they are easy to remember once you notice that six of them go on the parent and five go on a child. Most flexbox bugs are a property sitting on the wrong one of the two.

Two axes

A flex container has a main axis, the direction its items flow, and a cross axis at a right angle to it. In a row the main axis runs along the line of text; in a column it runs down the page. justify-content always works on the main axis and align-items always on the cross axis. That single fact replaces a lot of guessing.

Try it on a real nav bar

Every control below changes one declaration on the bar. The last one goes on a single item, which is the difference the rest of this lesson is built on.

HomeWorkAboutSign in

On the container

six cards · they go on the parent
1

Put children in a row

.nav {
  display: flex;
}

Goes on: the container.

The on-switch. The element becomes a flex container, and every direct child becomes a flex item: side by side, each as wide as its content, all as tall as the tallest one.

What it replaced: float: left on every child, then a clearfix on the parent.

2

Stack them instead

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

Goes on: the container.

The main axis turns to run top to bottom. Every other property keeps working and now points the new way, which is why a column that will not centre usually wants align-items, not justify-content.

3

Spread them along the main axis

.nav {
  display: flex;
  justify-content: space-between;
}

Goes on: the container.

Decides where the leftover space on the main axis goes: before the items, after them, or between them. It does nothing when there is no leftover space, so a row of items that already fills its container will not move.

4

Line them up across it

.nav {
  display: flex;
  align-items: center;
}

Goes on: the container.

The cross axis. The default is stretch, which is why flex children are equal height without being asked. center puts a small logo and a tall button on one shared middle line.

What it replaced: vertical-align: middle, which only ever worked on inline and table-cell boxes.

5

Space between, and only between

Widely available
.nav {
  display: flex;
  gap: 12px;
}

Goes on: the container.

One declaration on the container. No space at the outer edges, nothing to undo on the first or last child, and wrapped lines are spaced too.

What it replaced: a margin on every item and a :last-child rule to remove one of them.

6

Let them wrap

.tags {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

Goes on: the container.

Without it a flex container keeps everything on one line and squeezes the items. With it, items that do not fit move to a new line. Each line is laid out separately, so columns do not align between lines. If you need them to, that is a grid.

On an item

five cards · they go on a child
7

Take the space that is left

.sidebar { flex: 0 0 200px; }
.content { flex: 1; }

Goes on: the item.

flex is three values: grow, shrink, basis. The sidebar will not grow, will not shrink, and starts at 200px. The content has flex: 1, so it takes whatever remains. Two items with flex: 1 split the remainder evenly.

What it replaced: a float and a margin-left equal to the sidebar width, recalculated by hand on every change.

8

Push one item to the far end

Widely available
.sign-in {
  margin-inline-start: auto;
}

Goes on: the item.

An auto margin in a flex container absorbs all the free space on that side. One line on one item, and it stays correct when a fourth link is added. space-between cannot do this with three groups.

What it replaced: an empty spacer div with flex: 1.

9

Stop long text from breaking the row

.media-body {        /* the flex item */
  min-width: 0;
}
.media-body .title {  /* the text inside it */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

Goes on: the item.

The most common flexbox bug. A flex item will not shrink below the width of its content, because its min-width starts as auto. So the ellipsis you put on the title never triggers: the flex item around it refuses to get narrower, and the button leaves the card. min-width: 0 on the flex item gives it permission to shrink. (overflow: hidden on the item has the same effect, as a side effect.)

10

Align one item differently

.badge {
  align-self: flex-start;
}

Goes on: the item.

align-items sets the cross-axis alignment for every item. align-self overrides it for one. There is no justify-self in flexbox: on the main axis, use an auto margin.

11

Change the visual order

.promo {
  order: -1;
}

Goes on: the item.

Items paint in order of their order value, lowest first, and the default is 0.

Careful. This moves the pixels and nothing else. Keyboard focus and screen readers still follow the HTML. If the Tab key now jumps around the screen, the fix is to reorder the HTML, not the CSS.

Practice

  1. In the sandbox above, make the bar read: logo on the left, links together, “Sign in” alone on the right. There are two ways. Find both, then add a fifth link in your head and decide which one survives.
  2. Open a page you built, find a flex row with a long title in it, and shrink the window until it breaks. Add card nine to the flex item around the title and shrink again.
  3. Open DevTools on any flex container and click the flex badge next to it in the Elements panel. The browser draws the axes and the free space for you, which is the fastest way to see why justify-content is doing nothing.

Check yourself

You set justify-content: center on a column and the items will not centre left to right. Why?

In a column the main axis runs top to bottom, so justify-content is moving the items vertically. Left to right is now the cross axis: use align-items: center.

A row has an avatar, a name and a “Follow” button. A long name pushes the button off the card. Which card fixes it, and where does it go?

Card nine, on the flex item that holds the name, not on the row. That item is the one refusing to shrink, so it is the one that needs min-width: 0.

Why does space-between stop being the right tool when a nav bar gets a third group?

It spaces every item evenly, so three groups land at the left, the exact middle and the right. Usually you want two of them together. Put them side by side with gap and push the last one away with card eight, an auto margin.

The mental model to keep

Flexbox is a conversation between one parent and its direct children about one line of space. The parent decides direction, distribution and gaps. A child decides how much of the line it takes and whether it opts out of the group’s alignment. When a declaration does nothing, check which of the two you put it on. Two dimensions at once is the next lesson, CSS Grid.

Last reviewed 2026-09-18. Browser status on this page is read from the web-features dataset when the site is built, not typed. The page prints as its eleven cards.