CSS Flexbox: axes, alignment, and flexible sizing · Lesson 2 of 5

Lesson 02: Two axes, two properties

Lesson objectives:

  • Name the main axis and the cross axis of a flex container.
  • Match justify-content to the main axis and align-items to the cross axis.
  • Center an item horizontally and vertically on purpose, not by luck.

Prerequisites: Lesson 01 (display: flex puts items on the main axis) | Previous << 01 | Next 03 >>

You typed justify-content to move it down, and it went sideways

This is the single most common Flexbox frustration: you want to nudge an item down, you reach for justify-content, and the item slides sideways instead. Or you set align-items hoping to center horizontally and nothing happens. Neither property is broken. They each act on a different axis, and until you can see those two axes, picking between them is a coin flip. This lesson makes the two axes visible, then hangs one property on each.

Explanation

A flex container has two axes at right angles. The main axis is the one your items line up along — horizontal by default, the direction from Lesson 01. The cross axis runs perpendicular to the main axis1. With the default row direction, main is left-to-right and cross is top-to-bottom. The formal definition is the same: the main axis is the primary axis flex items are laid out along, and the cross axis is perpendicular to it2.

Now the payoff. There are two alignment properties, and each one owns exactly one axis:

  • justify-content aligns the items along the main axis — the direction flex-direction set the flow in1.
  • align-items aligns the items along the cross axis1.

So with a default row: justify-content moves items left/right, and align-items moves them up/down. That is the whole rule. "Justify" for the main axis, "align" for the cross axis. When you reach for the wrong one, the item moves along the wrong axis — exactly the sideways-instead-of-down bug.

The diagram below has the two axes and the two properties. flex-direction is row. Click the axis that justify-content spreads your items along.

Once you can point at the axes, centering is no longer a memorized incantation. To center an item, you align it on both axes at once: justify-content: center centers along the main axis, and align-items: center centers along the cross axis3. Two properties, one per axis.

The container below is already display: flex and has a fixed height, so both axes have room. Center the card in both directions.

If you set only justify-content: center, the card centers left-to-right but hugs the top — because you only handled the main axis. That missing second property is the classic "why is it centered horizontally but not vertically?" moment.

The values each property accepts

Naming the axis is half the job; the other half is naming a position on it. Both properties take the same core vocabulary, and the words are about the ends of an axis, not about screen edges3:

  • flex-start / flex-end — the main-start or main-end side for justify-content, the cross-start or cross-end side for align-items.
  • center — the middle of that axis.
  • space-between — takes all the spare space left after the items are laid out and shares it evenly between them, so the first and last items sit flush against the two ends3.
  • space-around — same idea, but each item gets a half-size space on either end, so the outer edges get half the gap the interiors do3.
  • space-evenly — every space including the outer two is full-size3.

Two of these belong only to align-items, because they need a cross axis to work against. stretch is the initial value of align-items: it is why flex items default to the height of the tallest sibling, or the container's height when one is set3. And baseline lines items up by the baseline of their text rather than by their boxes, which is what you want when a large heading and small label must read as sitting on the same line.

One more distinction that keeps justify-content from having a twin: justify-items is ignored in flex layouts1. On the main axis, flex treats the items as one group, so there is no per-item main-axis alignment property to reach for. That asymmetry is real and worth remembering rather than rediscovering.

Aligning one item differently with align-self

align-items sets the alignment for every item as a group. When one item needs to break ranks, the property is align-self, set on the item rather than the container; it takes all the same values as align-items, plus auto, which hands the decision back to the container3.

Note the pattern this establishes: container properties (justify-content, align-items) decide for the group, item properties (align-self, and the sizing properties in Lesson 04) decide for one box. When a property refuses to work, checking whether you put a container property on an item — or the reverse — resolves a surprising share of Flexbox bugs.

There is no justify-self in flexbox for the reason above. To push one item away from the group along the main axis, the idiom is an auto margin: margin-left: auto consumes all the free space it can on that side, which is how a nav pins the last link to the right while the rest stay left3.

Worked example (follow along)

You want a "Save" button pinned to the right edge of a toolbar and vertically centered in it:

Walking the axes: the main axis is horizontal (row default), so justify-content: flex-end pushes the item to the main-end — the right edge. The cross axis is vertical, so align-items: center centers the item top-to-bottom in the 56px height. Each property named its axis and its position; nothing was guesswork.

Your turn (faded example)

You want a badge in the bottom-left corner of a flex container that is display: flex with a set height. Fill in the two values:

Answer: justify-content: flex-start (main-start is the left edge) and align-items: flex-end (cross-end is the bottom). Read each line as "which axis, which end," and the corner falls out: left comes from the main axis, bottom comes from the cross axis.

Summary + what's next

A flex container has two perpendicular axes. justify-content aligns along the main axis; align-items aligns along the cross axis. Centering is just doing both. But notice we kept saying "horizontal by default" — that default is set by flex-direction, and the next lesson flips it. Once the main axis points down instead of across, justify-content moves items up and down, and that surprise is where a lot of people give up. Let's make it obvious instead.

Footnotes

  1. MDN: Basic concepts of flexbox — https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Flexible_box_layout/Basic_concepts 2 3 4

  2. W3C: CSS Flexible Box Layout Module Level 1 — https://www.w3.org/TR/css-flexbox-1/

  3. MDN: Aligning items in a flex container — https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Flexible_box_layout/Aligning_items 2 3 4 5 6 7 8

Exercises

01

In your own .html file, make a display: flex container with a fixed height and one child. Center the child both ways. Then delete align-items and reload to see what the cross axis was doing.

Level 1 (warm-up)
Done criteria · checked locally
02

Place four positions in turn using only justify-content and align-items: top-left, top-right, bottom-left, bottom-right. Predict each pair before you reload.

Level 2 (advanced)
Done criteria · checked locally

My note

Jot down thoughts, sticking points, things you didn't get. Written to this course's appendix only — the lesson file is never touched.