CSSBeginner

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.

All CSS lessons

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: flex on 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-basis is the item’s starting size along the main axis (its width in a row). It works like width, but it is the “ideal” size, not a fixed one.
  • flex-grow says how much of the leftover space the item may take. 0 (the default) means “do not grow”.
  • flex-shrink says how much the item may shrink if there is not enough space. 1 (the default) means “shrink if needed”. 0 means “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: 1 and 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: flex on the children instead of the parent.
  • Expecting grandchildren to be flex items. Only direct children are.
  • Using float, clear or vertical-align on flex items. They are ignored.
  • Forgetting that the axes swap when flex-direction is column.
  • Using width and being surprised when the item shrinks. Flex items can shrink below their width. Use flex: 0 0 200px (or flex-shrink: 0) if the size must stay fixed.
  • Overusing order and 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

  1. Click Practice in Editor. Look at the .row rule: add flex-direction: row-reverse and watch the order flip, then set it back.
  2. Turn the .column container into a flex container with flex-direction: column and gap: 10px. Which direction do the boxes go?
  3. Make the three items in .sizes as in the example, then change them to flex: 1, flex: 1, flex: 1. What happens to the widths?
  4. Give the .size-fixed item a very long word and flex-shrink: 1, then 0. Which one overflows?
  5. Move the first box to the end of .order-demo using order, without touching the HTML.
  6. Try the effect of display: inline-flex on .row. How is the container different from display: flex?

Recap

  • display: flex on 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.
  • gap adds space between items.
  • flex-grow, flex-shrink and flex-basis decide how items share space. The flex shorthand sets them as grow, shrink, basis: flex: 1 shares the space equally, flex: 0 0 200px stays fixed.
  • order changes the visual order only. Use it sparingly.
  • Next you will learn to align items and let them wrap onto several lines.