#The flex model: main axis and cross axis
Addeddisplay: flex turns an element into a flex container, and its direct children (only those, not grandchildren) become flex items. Flexbox lays the items out in one direction at a time: along a line, the main axis, set by flex-direction. The other direction, at right angles to it, is the cross axis. With the default flex-direction: row the main axis runs in the inline direction (left to right in English) and the cross axis top to bottom; with column they swap.
Every flex property is defined in terms of those two axes, not "horizontal" and "vertical". justify-* works along the main axis; align-* works across it. That's why justify-content: center centres horizontally in a row but vertically in a column. The mental model: the items are beads on a string. justify-content slides the beads along the string; align-items moves each bead up or down off the string; flex-direction turns the whole string around.
Two defaults explain most first impressions of flexbox: items sit in a single line and don't wrap (flex-wrap: nowrap), and items stretch across the cross axis to fill the line (align-items: normal, which behaves as stretch for flex items). That's why a row of flex items becomes equal height for free.
.row, .col { display: flex; width: 300px; background: #f1f5f9; margin-bottom: 10px; }
.row { height: 80px; }
.col { flex-direction: column; height: 140px; }
.item { background: #93c5fd; box-shadow: inset 0 0 0 1px #f1f5f9; }
.row .item { width: 60px; } /* main size in a row */
.col .item { height: 40px; } /* main size in a column */<div class="row"><div class="item">1</div><div class="item">2</div><div class="item">3</div></div>
<div class="col"><div class="item">1</div><div class="item">2</div><div class="item">3</div></div>- In
.rowthe main axis is horizontal. Each item is 60px wide (its main size), and the items are placed one after another from the main-start edge: 0, 60 and 120px. Unlike blocks, they don't stack. - Nothing sets their height, so the default alignment stretches them across the cross axis: each is 80px, the full height of the container.
- In
.col(flex-direction: column) the main axis is vertical. Each item's main size is now its 40px height, and they are placed at 0, 40 and 80px down. - The cross axis is now horizontal, so they stretch to the container's full 300px width, like blocks would.
- Same items, same properties; only the axes turned. The computed
align-itemsisnormal, which for flex items means stretch.
Becoming a flex item changes a box in two ways people trip over. Its display is blockified (an inline span becomes block, so width and height apply), and margins between flex items never collapse, unlike margins between blocks (see Margin collapsing).
.flexcol { display: flex; flex-direction: column; background: #f1f5f9; margin-bottom: 10px; }
.blockcol { background: #f1f5f9; }
.flexcol span, .blockcol div { margin: 10px 0; height: 20px; width: 120px; background: #fde68a; }<div class="flexcol"><span id="f1">span</span><span id="f2">span</span></div>
<div class="blockcol"><div id="b1">div</div><div id="b2">div</div></div>- The
spans are flex items, so their computeddisplayisblockandwidth: 120pxtakes effect. - Between the two flex items there are 20px: the first one's 10px bottom margin plus the second one's 10px top margin. Flex items' margins add up.
- Between the two block
divs there are only 10px: adjacent vertical margins in block layout collapse into the larger one. - The first flex item's top margin stays inside its container (10px from its top). The first block's top margin collapses through its parent (which has no padding or border) and pushes the parent down instead, so the
divsits flush with the parent's top. A flex container establishes a new formatting context, which never lets margins collapse through it.
row means "the inline direction", so in a right-to-left document a row starts at the right. row-reverse and column-reverse swap main-start and main-end. Both are visual only: the DOM order, and so the reading and tab order, don't change.
.r { display: flex; width: 300px; height: 30px; background: #f1f5f9; margin-bottom: 8px; }
.r i { width: 60px; flex: none; background: #c4b5fd; font-style: normal; text-align: center; box-shadow: inset 0 0 0 1px #f1f5f9; }
.rev { flex-direction: row-reverse; }<div class="r" id="ltr"><i>1</i><i>2</i><i>3</i></div>
<div class="r" id="rtl" dir="rtl"><i>1</i><i>2</i><i>3</i></div>
<div class="r rev" id="rev"><i>1</i><i>2</i><i>3</i></div>- In
#ltrthe row starts at the left: item 1 at 0px, 2 at 60px, 3 at 120px. - In
#rtl(dir="rtl") the inline direction runs right to left, so main-start is the right edge: item 1 is at 240px (its right edge touches the container's right edge), then 180, then 120. row-reversein a left-to-right page gives the same picture by swapping main-start and main-end. Note that the items also pack towards the right now:justify-content: flex-startmeans "towards main-start", which is the right in this case.- Use
dir/writing modes for languages, and avoid*-reversefor content whose order matters (see theordergotcha in Flex container properties).
.box { display: flex; flex-direction: column; justify-content: center; align-items: flex-end;
width: 300px; height: 200px; }
.item { width: 60px; height: 40px; }Show answer
Vertically centred and against the right edge: its top-left corner is at (240, 80). In a column, justify-content works vertically and align-items horizontally.
.box { display: flex; flex-direction: column; justify-content: center; align-items: flex-end; width: 300px; height: 200px; background: #f1f5f9; }
.item { width: 60px; height: 40px; background: #93c5fd; }<div class="box"><div class="item"></div></div>flex-direction: columnmakes the main axis vertical.justify-content: centershares the free main-axis space equally:200 − 40 = 160px, 80px above and 80px below, so the top is at 80px.align-items: flex-endaligns on the cross axis, now horizontal, to the cross-end edge: the right.300 − 60 = 240pxfrom the left.- If you swapped the direction back to
row, the same two declarations would put the item at (120, 160): centred horizontally, at the bottom.