DevPath · Learn to code ESPTEN

Flexbox in depth

The flex container: axes and distribution

The two-axis model

How many times have you fought to center something vertically or evenly space a row of elements? Flexbox exists for exactly that: aligning and distributing anything without the struggle. And vertical centering, that old headache, becomes a couple of lines.

When you apply display: flex to an element, it becomes a flex container and its direct children become flex items. What sets flexbox apart from everything before it is that it reasons in terms of two axes, not absolute rows and columns:

The key concept: justify-content aligns along the main axis and align-items aligns along the cross axis. Which axis is which is decided by flex-direction.

flex-direction: who is the main axis

.container {
  display: flex;
  flex-direction: row;     /* default: horizontal main axis → */
}

With row the main axis goes from left to right, so justify-content distributes horizontally and align-items aligns vertically. With column the roles are swapped:

.container {
  display: flex;
  flex-direction: column;  /* vertical main axis ↓ */
}

Now justify-content distributes vertically and align-items horizontally. ⚠️ CLASSIC TRAP: mixing up the two axes is the number one flexbox mistake. Don't memorize "justify = horizontal", memorize "justify = main axis" and let flex-direction decide which axis that is.

There are also row-reverse and column-reverse, which invert the visual order of the items without touching the HTML.

justify-content: distribute the main axis

justify-content decides what to do with the leftover space on the main axis:

.bar {
  display: flex;
  justify-content: space-between; /* ends pushed apart, gap in the middle */
}
Value Effect
flex-start Items at the start (default).
center Items grouped in the center.
flex-end Items at the end.
space-between First and last pushed to the edges; equal gaps.
space-around Equal gap around each item (half at the edges).
space-evenly Exactly equal gaps, including at the edges.

align-items: align the cross axis

.container {
  display: flex;
  align-items: center;   /* centers the items on the cross axis */
}

Its default value is stretch: the items are stretched to fill the whole height of the container (in a row). That's why, if you set display: flex on a row of cards with different content, they all end up with the same height "for free", with no need to match them up by hand. Other values: flex-start, flex-end, baseline.

flex-wrap: allow multiple lines

By default the items don't wrap: they shrink to fit. With flex-wrap: wrap you allow them to move to a new line when they don't fit:

.gallery {
  display: flex;
  flex-wrap: wrap;   /* nowrap (default) | wrap | wrap-reverse */
}

gap: spacing without margins

gap defines the space between items without adding it at the edges, avoiding the old margin hacks with "the last one without margin":

.container {
  display: flex;
  gap: 16px;            /* same horizontal and vertical gap */
  gap: 8px 24px;        /* row column: 8px between rows, 24px between columns */
}

With these six container properties you already solve most of your day-to-day layouts. The fine control lives in the items, and that's exactly what comes next.

Put this into practice

DevPath is a hands-on course: you read the theory here; in the app you put it into practice with exercises that really run, offline.

Start free in the app →
The items: grow, shrink, basis, self and order →