skip to content

In a CSS flex container, what are the main axis and the cross axis, and what changes when flex-direction is set to column?

level: middleimportance: must knowfreq 80%

answer

  1. one direction at a time
  2. the second axis is derived, not fixed
  3. start and end edges, not left and top
  4. justify versus align naming
  5. column swaps which property does what

basics

~20 s

flex-direction picks the main axis, the direction items are placed in, and the cross axis is always perpendicular to it. With flex-direction: column the main axis becomes vertical, so justify-content now positions items vertically and align-items horizontally.

solid answer

~40 s

Flexbox lays items out along one axis at a time. `flex-direction` chooses that **main axis** — horizontal for `row`, vertical for `column` — and the **cross axis** is whatever runs perpendicular to it. Each axis has a start and an end edge, which is what `flex-start` and `flex-end` refer to; they are not synonyms for left and top. The property split follows the naming: `justify-content` distributes items along the main axis, `align-items` and `align-self` position them on the cross axis, and the `flex-grow`/`flex-shrink`/`flex-basis` trio always sizes the **main** dimension. So switching to `column` swaps everything: `justify-content` becomes vertical, `align-items` becomes horizontal, `flex: 1` now distributes height instead of width, and an item's `width` is now its cross size, which the flex algorithm leaves alone.

code

css · 14 lines
css
.row {
  display: flex;
  flex-direction: row;
  justify-content: center; /* horizontal: main axis */
  align-items: center;     /* vertical:   cross axis */
}

.column {
  display: flex;
  flex-direction: column;
  min-height: 300px;       /* free space to distribute */
  justify-content: center; /* vertical:   main axis */
  align-items: center;     /* horizontal: cross axis */
}

go deeper

for a junior

Be able to say that flex-direction sets the main axis, that the cross axis is perpendicular to it, and that column makes the main axis vertical.

for a middle

Explain the mapping property by property: justify on the main axis, align on the cross axis, and the flex sizing trio always negotiating the main dimension. Expect to be asked what column changes.

for a senior

Demonstrate the diagnosis: when a responsive layout flips to column and the centring breaks, name the axis swap as the cause rather than adding both properties and hoping. Note that a content-height column has no free space to distribute.

for a principal

Own the convention that keeps this from recurring: axis-relative keywords over physical sides, and direction changes made at a single container rather than scattered, so a breakpoint switch does not silently reinterpret every alignment rule beneath it.

## One axis at a time Flexbox is a one-dimensional layout system: it arranges items along a single line at a time. `flex-direction` decides which direction that line runs, and everything else in the model is defined relative to it. - `row` (the initial value): the main axis is horizontal; items are placed left to right in a standard left-to-right horizontal writing mode. - `row-reverse`: still horizontal, but placement starts from the opposite end. - `column`: the main axis is vertical; items are placed top to bottom. - `column-reverse`: vertical, starting from the bottom. The **cross axis** is always perpendicular to the main axis. It is not "the vertical one" — it is vertical only for as long as the main axis is horizontal. ## The four edges Each axis has two edges: main-start and main-end, cross-start and cross-end. Items are packed from main-start toward main-end; when wrapping is enabled, the resulting lines stack from cross-start toward cross-end. Every keyword ending in `-start` or `-end` names one of these edges rather than a physical side, which is precisely why `justify-content: flex-start` pushes items to the **top** of a `column` container. ## Which property follows which axis | Property | Axis | Declared on | | --- | --- | --- | | `justify-content` | main | container | | `align-items`, `align-self` | cross | container, item | | `align-content` | cross (stacking of wrapped lines) | container | | `flex-grow`, `flex-shrink`, `flex-basis` | main | item | The naming is a dependable mnemonic: `justify-*` acts on the main axis, `align-*` acts on the cross axis, and the `flex-*` sizing properties always size the main dimension. ## What flex-direction: column actually changes In a horizontal writing mode, switching a container from `row` to `column`: - makes `justify-content` move items up and down instead of left and right; - makes `align-items` move items left and right instead of up and down; - makes `flex-basis` and shorthands like `flex: 1` distribute **height**, because an item's main size is now its height; - means the default cross-axis stretch now stretches items to the container's **width** rather than its height; - makes `flex-wrap: wrap` create new columns rather than new rows. Nothing else changes. The container is still a block-level box, the children are still flex items, and no additional dimension of layout has appeared — a column flex container is still one-dimensional. ## The classic bug Someone centres a toolbar with `justify-content: center`, later switches the container to `column` at a small breakpoint, and the horizontal centring vanishes. The declaration did not stop working: it still centres on the main axis, and the main axis is now vertical. The property that now controls horizontal position is `align-items`. ```css .stack { display: flex; flex-direction: column; align-items: center; /* horizontal — cross axis */ justify-content: center; /* vertical — main axis */ } ``` A second, closely related surprise: main-axis distribution in a `column` container often looks like it does nothing. That is because a block-level container's height is content-based, so there is no free space on the vertical main axis to distribute. Give the container a `height`, a `min-height`, or make it a flex item that grows, and the same declaration starts behaving. ## Main size and cross size The specification talks about an item's *main size* and *cross size* rather than width and height, because which physical dimension those map to depends on `flex-direction`. In a row container, `width` is the main size — the flex algorithm may grow or shrink it — and `height` is the cross size. In a column container the roles swap: `width` becomes the cross size and is left to ordinary sizing and stretching, while `height` is what `flex-grow` and `flex-shrink` negotiate. This is why a fixed `width` on an item behaves so differently in the two directions. ## The reverse values `row-reverse` and `column-reverse` swap main-start with main-end. Items are laid out from the far end, and main-axis alignment follows them, so `flex-start` in a `row-reverse` container is the right-hand edge. What they do **not** change is the document: DOM order, painting order and keyboard focus order all stay in source order, so a reversed visual sequence no longer matches the order a keyboard or screen-reader user encounters. They also flip which edge overflowing content spills toward, which is a common source of confused scroll behaviour. ## Axes are relative, not physical One last framing that pays off later: `row` and `column` are defined against the container's inline and block axes, not against the screen. Change the writing direction and the physical meaning of `row` changes with it — which is exactly what makes flex-relative keywords worth using instead of hardcoded sides.

  • What exactly does flex-direction: row-reverse change, and what does it leave alone?
    It swaps main-start and main-end, so items are laid out from the right in a left-to-right context and main-axis alignment flips with them. It leaves the document alone: DOM order, painting order and keyboard focus order stay in source order, so the visual sequence and the tab sequence diverge. It also flips which edge overflow spills toward.
  • In a column container, why does main-axis distribution often appear to do nothing?
    Because there is no free space. A block-level container's height is determined by its content, so the items already fill the main axis exactly and there is nothing left to distribute. Give the container a height or min-height, or let it grow as a flex item itself, and the distribution becomes visible.
  • How do you work out which axis a property acts on without memorising a table?
    Read the prefix. Anything named `justify-*` acts on the main axis, anything named `align-*` acts on the cross axis, and the `flex-*` sizing properties always size the main dimension. Then ask which physical direction the main axis currently points, which is entirely decided by `flex-direction`.

saying these in an interview costs you the question

  • Says justify-content always centres things horizontally
  • Thinks the cross axis is always the vertical one
  • Believes flex-direction: column gives two-dimensional layout
  • Assumes flex-basis always resolves against width
  • Reads flex-start as a synonym for the left edge

context