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: flexordisplay: 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,columnorcolumn-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).
<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.
.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.
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.
.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.
.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.
.button {
display: inline-flex;
align-items: center; /* Topic 7.2 */
gap: 6px; /* Topic 7.4 */
}Try it yourself
- 1
Predict the column widths
In the first example, change
.flextodisplay: flex; flex-direction: column;and deletewidth: 50pxfrom the items. Predict how wide the items become before you run it. (They stretch across the cross axis, which is now horizontal: 240px.) - 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,rowstarts at the right edge, so A moves to x = 130. - 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'sdisplaynow. (It'sinlineagain: its parent<p>isn't a flex container, so only the<p>is a flex item.)
Code & diagrams
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
Console
Nothing logged yet.Expected console output
block: (0,0) (0,30) (0,60)
flex: (0,0) (50,0) (100,0)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
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)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
Console
Nothing logged yet.Expected console output
span display: block
span height: 100
auto height: 100
fixed height: 60
child elements: 3 | child nodes: 7Break 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; }.
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.
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: flexon a parent also fixes "margin escaping the parent" bugs. - ▸
::beforeand::afteron 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::aftertakes part in your layout as an empty item. - ▸
Children with
position: absoluteare 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 ajustify-content: centercontainer may appear centred. - ▸
Some elements can't become flex containers in every browser, or only partly: historically
<button>,<fieldset>and<summary>. Modern browsers supportdisplay: flexon<button>, but if you need to support old Safari, wrap the content in a<span>and make that the flex container.
Remember this
- 1
A flex container is any element with
display: flex(ordisplay: 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
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: rowin 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-contentworks on the main axis,align-itemson the cross axis (Topic 7.2). - 3
flex-directionchooses the main axis.row(the default) runs in the direction text runs,row-reverseruns the opposite way,columnruns from top to bottom, andcolumn-reversefrom bottom to top. Change the direction and the axes swap: withcolumn, the main axis is vertical, sojustify-contentnow moves items up and down, andalign-itemsmoves them left and right. This swap confuses everyone once; it is the single most useful fact in this phase. - 4
rowis defined by the writing mode and text direction (Phase 6, Topic 6.1), not by "left to right". In a page withdir="rtl"(right to left, used for Arabic and Hebrew), arowstarts at the right edge. In a vertical writing mode,rowruns top to bottom. That's why Flexbox speaks of start and end, not left and right: the same CSS works for every language. - 5
Becoming a flex item changes a child's behaviour. Its outer display is blockified: a
<span>or an<a>becomes block-level, sowidth,heightand vertical margins all apply.floatandvertical-alignare 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
display: flexmakes the container itself a block-level box: it takes the full available width, like a<div>.display: inline-flexmakes 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 syntaxdisplay: block flexanddisplay: inline flex, which mean the same thing.
Explain it without notes
What is the difference between a flex container and a flex item?
Explain the main axis and the cross axis, and how flex-direction changes them.
What happens to a child element when it becomes a flex item?
What is the difference between display: flex and display: inline-flex?
Why can flex-direction: row-reverse be an accessibility problem?
Practice
Make a <nav> lay out its three <a> links in a row.
Make a .stack element place its children in a column from top to bottom, using Flexbox.
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-directionis 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
rowfollows 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: flexanddisplay: inline-flex.I know why reversed directions don't change tab order.