Command Palette

Search for a command to run...

Hectal
PHASE 7Intermediate ~27 min· topic 1 of 5

Topic 7.1

The Flex Container and Axes

In one line

display: flex turns an element into a flex container and its direct children into flex items, laid out along a main axis set by flex-direction; the cross axis runs at right angles to it, and every other Flexbox property is defined in terms of these two axes.

Think of it like this

Kids lining up for the school bus. The teacher says "line up", and they stand one after another in a single line. That line has a direction: front to back. If the teacher says "line up across the playground instead", the same kids stand side by side. Flexbox works like this teacher. The container is the line, the items are the kids, and flex-direction says which way the line runs.

Words you'll meet

New words in this topic, in plain English. Come back here whenever one feels fuzzy.

Flexbox
The CSS layout system for placing items in one row or one column and sharing out the space between them.
Flex container
An element with display: flex or display: inline-flex. It lays out its children with Flexbox.
Flex item
A direct child of a flex container. Only children count, not grandchildren.
Main axis
The direction the items are placed in, one after another. Set by flex-direction.
Cross axis
The direction at right angles to the main axis. In a row it runs top to bottom.
Main-start / main-end
The two ends of the main axis: where the first item goes, and where the line ends.
`flex-direction`
The property that picks the main axis: row, row-reverse, column or column-reverse.
Anonymous flex item
An invisible box the browser makes around loose text inside a flex container, so the text can be laid out like an item.
Blockified
Turned into a block-level box. Flex items are always blockified, even a <span>.

Step by step

01Start with three blocks

Three <div> children inside a parent stack from top to bottom. That's normal flow: block boxes each start on a new line (Phase 6, Topic 6.1).

index.htmlwhole filehtml
<div class="row">
  <div>A</div>
  <div>B</div>
  <div>C</div>
</div>

02Turn the parent into a flex container

Add one declaration to the parent, not the children. The children become flex items and line up along the main axis, which runs the way text runs: left to right in English.

Each item is only as wide as its content, and all of them stretch to the height of the tallest one.

style.csswhole filecss
.row {
  display: flex;
}

03Name the axes

With flex-direction: row, the main axis is horizontal and the cross axis is vertical. Every Flexbox property belongs to one of the two axes, so always ask "which way is my main axis?" first.

Name the axesdiagram
Rendering diagram…

04Turn the line into a column

Set flex-direction: column. The main axis now runs top to bottom and the cross axis left to right. The items stack again, but they are still flex items: they can grow, shrink and be aligned with every Flexbox property.

style.csswhole filecss
.row {
  display: flex;
  flex-direction: column; /* main axis: top to bottom */
}

05Reverse the direction

row-reverse and column-reverse swap main-start and main-end. Item A now sits at the right (or the bottom). Only the picture changes: the HTML order, the reading order for screen readers and the Tab order stay A, B, C.

style.csswhole filecss
.row {
  display: flex;
  flex-direction: row-reverse; /* A ends up on the right */
}

06Pick block or inline

display: flex gives a full-width container that starts on its own line. display: inline-flex gives a container that is as wide as its content and sits inside text, which suits a button with an icon and a label.

style.csswhole filecss
.button {
  display: inline-flex;
  align-items: center; /* Topic 7.2 */
  gap: 6px;           /* Topic 7.4 */
}

Try it yourself

  1. 1

    Predict the column widths

    In the first example, change .flex to display: flex; flex-direction: column; and delete width: 50px from the items. Predict how wide the items become before you run it. (They stretch across the cross axis, which is now horizontal: 240px.)

  2. 2

    Right to left

    In the second example, add dir="rtl" to the first .box. Predict where A goes, then check the console. In a right-to-left context, row starts at the right edge, so A moves to x = 130.

  3. 3

    Grandchildren are not flex items

    In the third example, wrap the <span> in a <p>: <p><span>a span</span></p>. Predict the span's display now. (It's inline again: its parent <p> isn't a flex container, so only the <p> is a flex item.)

Code & diagrams

The same children, before and after display: flex New tab

Each pair is (x, y) of an item inside its container, in px. In normal flow the blocks stack (y grows by 30). In the flex container they sit side by side on the main axis (x grows by 50). Only the parent changed.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

block: (0,0) (0,30) (0,60)
flex:  (0,0) (50,0) (100,0)
The four flex-direction values New tab

Item A (orange) is always first in the HTML. `row-reverse` puts it at the right end (x = 180 - 50), `column-reverse` at the bottom (y = 90 - 30), because the main-start edge moved. The inline `style` attributes are only there so each box shows its own value.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

row -> A at (0,0)
row-reverse -> A at (130,0)
column -> A at (0,0)
column-reverse -> A at (0,60)
What changes for the children New tab

The `<span>` is blockified (`display: block`). Items without a height stretch to the container's 100px; the one with `height: 60px` keeps it. The loose text becomes an anonymous flex item: you can see it laid out, but it isn't an element, so `children` doesn't list it and you can't style it with a selector.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

span display: block
span height: 100
auto height: 100
fixed height: 60
child elements: 3 | child nodes: 7
The two axes for row and columndiagram
Rendering diagram…

Break it on purpose

Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.

Break #1

Put display: flex on the children

In the first example, change the last rule to .flex > div { display: flex; } instead of .flex { display: flex; }.

terminal
$ Console
── what you'll see ──
flex: (0,0) (0,30) (0,60)

Break #2

Use row-reverse to fix the reading order

A designer wants the "Next" button before "Back", so the HTML is <button>Back</button><button>Next</button> and the container gets flex-direction: row-reverse.

terminal
$ Keyboard
── what you'll see ──
Next is shown first, but pressing Tab focuses Back first, and a screen reader also reads Back first.

Myth vs fact

Myth

display: flex lays out everything inside the element.

Fact

It affects only the direct children. A grandchild is laid out by its own parent, with whatever display that parent has.

Myth

The main axis is always horizontal.

Fact

It follows flex-direction. With column the main axis is vertical, and justify-content moves items up and down.

Myth

row means left to right.

Fact

row follows the text direction and writing mode. In a right-to-left page it runs right to left.

Myth

row-reverse reverses the order for everyone.

Fact

Only for eyes. Tab order, screen readers and text selection still follow the HTML order.

Pro corner

Extra depth for experienced readers. New to this? Skip it for now and come back later.

  • ▸

    The spec calls the outer box the flex container and says it establishes a flex formatting context. Like a block formatting context (Phase 6), it contains floats and stops margins collapsing through it, so display: flex on a parent also fixes "margin escaping the parent" bugs.

  • ▸

    ::before and ::after on a flex container are real children of it, so they become flex items too. That's handy (a decorative line before a heading) and surprising when a clearfix ::after takes part in your layout as an empty item.

  • ▸

    Children with position: absolute are not flex items: they're taken out of flow. Their static position is still worked out as if they were the only item, which is why an absolutely positioned child of a justify-content: center container may appear centred.

  • ▸

    Some elements can't become flex containers in every browser, or only partly: historically <button>, <fieldset> and <summary>. Modern browsers support display: flex on <button>, but if you need to support old Safari, wrap the content in a <span> and make that the flex container.

Remember this

  1. 1

    A flex container is any element with display: flex (or display: inline-flex). Its direct children, and only those, become flex items. Grandchildren are not flex items; they lay out normally inside their own parent unless that parent is a flex container too. Plain text sitting directly inside the container is wrapped in an invisible anonymous flex item, so it takes part in the layout as well.

  2. 2

    The main axis is the direction items are placed in, one after another. The cross axis runs at right angles (90 degrees) to it. Each axis has a start and an end: with the default flex-direction: row in English, the main axis runs left to right (main-start is the left edge) and the cross axis runs top to bottom (cross-start is the top). Learn these four words, because every Flexbox property is named after them: justify-content works on the main axis, align-items on the cross axis (Topic 7.2).

  3. 3

    flex-direction chooses the main axis. row (the default) runs in the direction text runs, row-reverse runs the opposite way, column runs from top to bottom, and column-reverse from bottom to top. Change the direction and the axes swap: with column, the main axis is vertical, so justify-content now moves items up and down, and align-items moves them left and right. This swap confuses everyone once; it is the single most useful fact in this phase.

  4. 4

    row is defined by the writing mode and text direction (Phase 6, Topic 6.1), not by "left to right". In a page with dir="rtl" (right to left, used for Arabic and Hebrew), a row starts at the right edge. In a vertical writing mode, row runs top to bottom. That's why Flexbox speaks of start and end, not left and right: the same CSS works for every language.

  5. 5

    Becoming a flex item changes a child's behaviour. Its outer display is blockified: a <span> or an <a> becomes block-level, so width, height and vertical margins all apply. float and vertical-align are ignored on flex items. Margins of neighbouring flex items never collapse (in normal flow, two 20px vertical margins merge into 20px; between flex items they add up to 40px). And by default items stretch across the cross axis to fill the container, which is why a row of boxes comes out the same height.

  6. 6

    display: flex makes the container itself a block-level box: it takes the full available width, like a <div>. display: inline-flex makes the container inline-level: it is only as wide as its content and sits inside a line of text, like a button. The inside works the same in both. In modern CSS you may also see the two-value syntax display: block flex and display: inline flex, which mean the same thing.

Explain it without notes

01

What is the difference between a flex container and a flex item?

02

Explain the main axis and the cross axis, and how flex-direction changes them.

03

What happens to a child element when it becomes a flex item?

04

What is the difference between display: flex and display: inline-flex?

05

Why can flex-direction: row-reverse be an accessibility problem?

Practice

01

Make a <nav> lay out its three <a> links in a row.

02

Make a .stack element place its children in a column from top to bottom, using Flexbox.

03

A <div class="tag"> holds an icon <span> and some text. Make it sit inside a sentence, only as wide as its content, with the icon and text side by side.

Trade-offs

  • ↔

    Flexbox is one-dimensional: it lays out a single row or column at a time. That makes it perfect for toolbars and lists of unknown length, but when rows and columns must line up with each other, Grid (Phase 8) is the better tool.

  • ↔

    Reversing with flex-direction is quick, but it splits visual order from DOM order. Reordering the HTML costs a little more work and keeps keyboard and screen-reader users in step with what they see.

Done when you can

  • I can turn an element into a flex container and say which elements become flex items.

  • I can name the main axis and the cross axis for any flex-direction.

  • I know that row follows the text direction, not "left to right".

  • I can explain what happens to a <span>, floats and margins inside a flex container.

  • I can choose between display: flex and display: inline-flex.

  • I know why reversed directions don't change tab order.