CSS Flexbox Basics: Containers, Items, Direction and flex
Learn how Flexbox lays out items in a row or column, what the main and cross axes are, and how flex-direction, gap, flex-grow, flex-basis and order work.
What you will learn
Before Flexbox, putting boxes side by side meant clever tricks with floats and inline-blocks, and centering something vertically was a famous headache. Flexbox (the Flexible Box Layout) solves this properly. It is a one-dimensional layout system: it lays items out along one line, either a row or a column, and lets the browser handle the sizing and spacing for you. In this lesson you will learn the vocabulary (container, items, axes), how to set direction and spacing, and how items share the available space with flex.
The HTML we will style
All the examples use this one page. Every part has its own container and uses the same three coloured boxes.
<h1 class="page-title">Flexbox Lab</h1>
<!-- Part 1: a flex container with three items -->
<div class="row">
<div class="box box-1">1</div>
<div class="box box-2">2</div>
<div class="box box-3">3</div>
</div>
<!-- Part 2: changing the direction -->
<div class="column">
<div class="box box-1">A</div>
<div class="box box-2">B</div>
<div class="box box-3">C</div>
</div>
<!-- Part 3: how items share the space -->
<div class="sizes">
<div class="size size-fixed">fixed 120px</div>
<div class="size size-grow">flex: 1</div>
<div class="size size-grow-double">flex: 2</div>
</div>
<!-- Part 4: changing the visual order -->
<div class="order-demo">
<div class="box box-1">First in HTML</div>
<div class="box box-2">Second in HTML</div>
<div class="box box-3">Third in HTML</div>
</div>
| Selector | Element | Role |
|---|---|---|
.row |
the first <div> |
flex container for Part 1 |
.column |
the second <div> |
flex container for Part 2 (vertical) |
.sizes |
the third <div> |
flex container for Part 3 |
.order-demo |
the fourth <div> |
flex container for Part 4 |
.box |
the nine coloured <div>s |
flex items, with shared padding, colour and bold text |
.box-1, .box-2, .box-3 |
the first, second and third box in each group | background colours |
.size, .size-fixed, .size-grow, .size-grow-double |
the three items in Part 3 | items that each take space differently |
Without Flexbox
By default, each <div> is a block element, so the three boxes stack vertically and each one stretches to the full width. That is normal flow. Flexbox is how you change that.
Flex container and flex items
Flexbox always involves two kinds of element:
- The flex container is the parent. You turn it on with
display: flex. - The flex items are its direct children. They automatically start behaving as flex items.
/* the <div class="row"> is the flex container */
.row {
display: flex;
}
That single line puts the three .box children in a row, side by side. Nothing was written on the boxes themselves.
The most common beginner mistake: putting
display: flexon the items instead of on the container. The property always goes on the parent of the things you want to arrange.
Only direct children become flex items. A paragraph inside one of the boxes is not a flex item, and it is not affected by the container’s flex properties. (It can be a flex container itself if you give its parent display: flex. That is called nesting.)
display: inline-flex also exists. It makes a container that behaves like an inline element (it only takes up as much width as it needs), while its children are still flex items.
The two axes
Flexbox thinks in two directions:
- The main axis is the direction in which items are laid out.
- The cross axis is perpendicular to it.
flex-direction: row (the default)
main axis ----------------------->
+-----------------------------------------+ |
| [ 1 ] [ 2 ] [ 3 ] | | cross axis
+-----------------------------------------+ v
flex-direction: column
cross axis ----------------------->
+--------------------+ |
| [ A ] | | main axis
| [ B ] | |
| [ C ] | v
+--------------------+
This matters because the alignment properties you will meet next lesson (justify-content and align-items) are defined in terms of these axes, not “horizontal” and “vertical”. When you change direction, they swap.
flex-direction
flex-direction sets the main axis:
/* the <div class="column"> */
.column {
display: flex;
flex-direction: column;
}
| Value | Result |
|---|---|
row |
the default: left to right |
row-reverse |
right to left |
column |
top to bottom |
column-reverse |
bottom to top |
Reversing changes only the visual order. Screen readers and keyboard users still follow the HTML order, so do not use reverse to fix a bad source order.
gap: space between items
gap puts space between flex items without touching the outside edges, so you do not need margins on every child:
.row {
display: flex;
gap: 10px;
}
You can also set row-gap and column-gap separately, or two values: gap: 10px 20px means row gap first, then column gap. gap replaces the old pattern of adding margin-right to every item except the last.
Sizing flex items: flex-grow, flex-shrink, flex-basis
By default, items are only as wide as their content, and they bunch up at one end. The really powerful part of Flexbox is that you can tell items how to share the available space. Three properties are involved:
flex-basisis the item’s starting size along the main axis (its width in a row). It works likewidth, but it is the “ideal” size, not a fixed one.flex-growsays how much of the leftover space the item may take.0(the default) means “do not grow”.flex-shrinksays how much the item may shrink if there is not enough space.1(the default) means “shrink if needed”.0means “never shrink”.
The flex shorthand
You will almost always use the shorthand, which sets all three, in the order grow, shrink, basis:
.size-fixed { flex: 0 0 120px; } /* do not grow, do not shrink, always 120px */
.size-grow { flex: 1; } /* take 1 share of the leftover space */
.size-grow-double { flex: 2; } /* take 2 shares of the leftover space */
Together with a container:
/* the <div class="sizes"> */
.sizes {
display: flex;
gap: 10px;
}
/* all three <div class="size"> items */
.size {
padding: 20px;
color: white;
}
.size-fixed { flex: 0 0 120px; background-color: tomato; }
.size-grow { flex: 1; background-color: seagreen; }
.size-grow-double { flex: 2; background-color: royalblue; }
How the space is shared: the first item stays exactly 120px. The remaining space is split between the other two in the ratio 1 : 2, so the blue item ends up twice as wide as the green one, however wide the container is. Try changing the numbers.
Handy shortcuts you will see everywhere:
| Shorthand | Means | Typical use |
|---|---|---|
flex: 1 |
1 1 0%: grow, shrink, start from zero |
equal-width columns, a column that fills the rest |
flex: 0 0 200px |
do not grow or shrink, exactly 200px | fixed sidebars |
flex: auto |
1 1 auto: start from content size, then grow |
items sized by content that also stretch |
flex: none |
0 0 auto: do not grow or shrink |
items that must keep their size |
Equal columns in one line: give every child
flex: 1and they all get the same width, no matter how much text each has.
Shrinking and overflow
If the items together are wider than the container, and flex-shrink is 1, the items shrink to fit. Items with long unbreakable content (a wide image or code block) refuse to shrink below their content size. Add min-width: 0 to let them shrink, or flex-shrink: 0 if you want them to keep their size and let the container overflow or wrap.
order: changing the visual order
Every flex item has order: 0 by default. Items are shown from the lowest order to the highest, and items with equal values keep their HTML order. A negative value moves an item to the front:
/* the third box in the <div class="order-demo"> */
.order-demo {
display: flex;
gap: 10px;
}
.order-demo .box-3 {
order: -1;
}
Now the “Third in HTML” box appears first. As with row-reverse, only the visual order changes. Keyboard users still move through the page in HTML order, so use order sparingly.
Putting it together
*, *::before, *::after { box-sizing: border-box; }
body { font-family: Arial, Helvetica, sans-serif; }
.box {
padding: 20px;
color: white;
font-weight: bold;
}
.box-1 { background-color: tomato; }
.box-2 { background-color: seagreen; }
.box-3 { background-color: royalblue; }
/* Part 1 */
.row {
display: flex;
gap: 10px;
margin-bottom: 24px;
}
/* Part 2 */
.column {
display: flex;
flex-direction: column;
gap: 10px;
margin-bottom: 24px;
}
/* Part 3 */
.sizes {
display: flex;
gap: 10px;
margin-bottom: 24px;
}
.size {
padding: 20px;
color: white;
}
.size-fixed { flex: 0 0 120px; background-color: tomato; }
.size-grow { flex: 1; background-color: seagreen; }
.size-grow-double { flex: 2; background-color: royalblue; }
/* Part 4 */
.order-demo {
display: flex;
gap: 10px;
}
.order-demo .box-3 {
order: -1;
}
Common mistakes
- Putting
display: flexon the children instead of the parent. - Expecting grandchildren to be flex items. Only direct children are.
- Using
float,clearorvertical-alignon flex items. They are ignored. - Forgetting that the axes swap when
flex-directioniscolumn. - Using
widthand being surprised when the item shrinks. Flex items can shrink below theirwidth. Useflex: 0 0 200px(orflex-shrink: 0) if the size must stay fixed. - Overusing
orderand reverse directions, which make keyboard order differ from visual order. - Adding margins between items instead of using
gap. - Using Flexbox for everything. It is one-dimensional. For rows and columns together, Grid is a better fit (see the Grid lesson).
Practice
- Click Practice in Editor. Look at the
.rowrule: addflex-direction: row-reverseand watch the order flip, then set it back. - Turn the
.columncontainer into a flex container withflex-direction: columnandgap: 10px. Which direction do the boxes go? - Make the three items in
.sizesas in the example, then change them toflex: 1,flex: 1,flex: 1. What happens to the widths? - Give the
.size-fixeditem a very long word andflex-shrink: 1, then0. Which one overflows? - Move the first box to the end of
.order-demousingorder, without touching the HTML. - Try the effect of
display: inline-flexon.row. How is the container different fromdisplay: flex?
Recap
display: flexon a parent turns its direct children into flex items that line up in a row.- The main axis is the direction of the layout (set by
flex-direction) and the cross axis is perpendicular to it. gapadds space between items.flex-grow,flex-shrinkandflex-basisdecide how items share space. Theflexshorthand sets them as grow, shrink, basis:flex: 1shares the space equally,flex: 0 0 200pxstays fixed.orderchanges the visual order only. Use it sparingly.- Next you will learn to align items and let them wrap onto several lines.