CSS Flexbox tutorial: the complete guide to flexible layouts

CSS Flexbox tutorial: the complete guide to flexible layouts

Flexbox is a CSS layout module that lets you build flexible, adaptive layouts for your HTML elements. It is especially useful when a layout has to cope with different screen sizes and different devices.

With Flexbox you can align items horizontally or vertically, control the space between them and set the order in which they appear. It also gives you flexible ways to size items, which is exactly what a responsive layout needs.

To use Flexbox in your project, first declare a flex container with the CSS property display: flex or display: inline-flex on an HTML element. From there, the Flexbox properties control the layout of its children.

css
.container-flex {
    display: flex;
}

How to align items with Flexbox

One of the most useful things Flexbox does is align items flexibly. Several properties give you control over how items line up inside a flex container.

Horizontal alignment with justify-content

The justify-content property controls how items are aligned horizontally. 

justify-content: flex-start;

Item
Item

justify-content: center;

Item
Item

justify-content: flex-end;

Item
Item

justify-content: space-between;

Item
Item

justify-content: space-around;

Item
Item

justify-content: space-evenly;

Item
Item
css
/*aligns the items on the left edge*/
.container {
    justify-content: flex-start;
}
/*centres the items*/
.container {
    justify-content: center;
}
/*aligns the items on the right edge*/
.container {
    justify-content: flex-end;
}
/*spreads the items evenly between the left and right edges with no space at the edges*/
.container {
    justify-content: space-between;
}
/*spreads the items evenly between the left and right edges with the same amount of space at both edges*/
.container {
    justify-content: space-around;
}
/* spreads the items evenly between the left and right edges with the same amount of space at both edges and between each item */
.container {
    justify-content: space-evenly;
}

Vertical alignment with align-items

The align-items property controls how items are aligned vertically.

align-items: flex-start;

Item
Item

align-items: center;

Item
Item

align-items: flex-end;

Item
Item

align-items: stretch;

Item
Item
css
/* Align every item at the top */
.container {
    align-items: flex-start;
}

/* Align every item in the middle */
.container {
    align-items: center;
}

/* Align every item at the bottom */
.container {
    align-items: flex-end;
}

/*makes the items match the height of their content*/
.container {
    align-items: stretch;
}

How to control the space between items with Flexbox

Flexbox also lets you control the space between items. Several properties handle spacing inside a flex container.

Adding space between items with margin

The margin property sets the space between an element and the elements around it. Use it when you want to space items one by one.

css
/* Add 20px of space between each item */
.item {
    margin: 0 20px;
}

Adding space around an item with padding

The padding property sets the space between the edges of an element and its content. Use it to add space around a single item.

css
/* Add 20px of space around an item */
.item {
    padding: 20px;
}

Using gap to space items out

Since CSS Grid Layout, Flexbox can use gap to add space between items. The property sets a uniform gap between every item in a flex container.

css
/* Add 20px of space between all the items */
.container {
    gap: 20px;
}

It works together with row-gap and column-gap when you need different spacing on rows and on columns. Two things to keep in mind: it only applies to the direct children of the flex container, and you should check browser support before relying on it.

The Flexbox properties

Flexbox comes with a long list of properties for building flexible, adaptive layouts. This section goes through the ones you will actually use.

flex-direction

The flex-direction property sets the direction items are laid out in a flex container. There are four possible values: row, row-reverse, column and column-reverse. The default is row.

flex-direction: row;

Item 1
Item 2

flex-direction: row-reverse;

Item 1
Item 2

flex-direction: column;

Item 1
Item 2

flex-direction: column-reverse;

Item 1
Item 2
css
/* Lays the items out in a row (default) */
.container {
    flex-direction: row;
}

/* Lays the items out in a reversed row */
.container {
    flex-direction: row-reverse;
}

/* Lays the items out in a column */
.container {
    flex-direction: column;
}

/* Lays the items out in a reversed column */
.container {
    flex-direction: column-reverse;
}

flex-wrap

The flex-wrap property defines whether the items of a flex container are laid out on a single line or on several lines. There are three possible values: nowrap (default), wrap and wrap-reverse, which stacks the lines in reverse order.

flex-wrap: nowrap;

Item 1
Item 2
Item 3
Item 4
Item 5
Item 6
Item 7

flex-wrap: wrap;

Item 1
Item 2
Item 3
Item 4
Item 5
Item 6
Item 7
css
/* Lays the items out on a single line (default) */
.container {
    flex-wrap: nowrap;
}

/* Lays the items out over several lines */
.container {
    flex-wrap: wrap;
}

flex-flow

The flex-flow property is a shorthand for flex-direction and flex-wrap:

css
/* Lays the items out in a row and over several lines */
.container {
    flex-flow: row wrap;
}

justify-content

The justify-content property sets how items are aligned on the horizontal axis (x) of a flex container. The possible values are flex-start, center, flex-end, space-between, space-around and space-evenly. The default is flex-start.

css
/*aligns the items on the left edge*/
.container {
    justify-content: flex-start;
}
/*centres the items*/
.container {
    justify-content: center;
}
/*aligns the items on the right edge*/
.container {
    justify-content: flex-end;
}
/*spreads the items evenly between
the left and right edges with no space at the edges*/
.container {
    justify-content: space-between;
}
/*spreads the items evenly between the left edge
and the right edge with the same amount of space at both edges*/
.container {
    justify-content: space-around;
}
/* spreads the items evenly between the left edge
and the right edge with the same amount of space at both edges and
between each item */
.container {
    justify-content: space-evenly;
}

align-items

The align-items property sets how items are aligned on the vertical axis (y) of a flex container. The possible values are flex-start, center, flex-end, baseline and stretch. The default is stretch.

css
/* Align every item at the top */
.container {
    align-items: flex-start;
}

/* Align every item in the middle */
.container {
    align-items: center;
}

/* Align every item at the bottom */
.container {
    align-items: flex-end;
}

/*makes the items match the height of their content*/
.container {
    align-items: stretch;
}

align-content

The align-content property is similar to align-items, but it acts on the lines of a multi-line flex container. It accepts the same values as align-items, plus space-between, space-around and space-evenly to distribute the lines.

align-content: flex-start;

Item 1
Item 2
Item 3
Item 4
Item 5
Item 6
Item 7
Item 8
Item 9
Item 10
Item 11
Item 12

align-content: center;

Item 1
Item 2
Item 3
Item 4
Item 5
Item 6
Item 7
Item 8
Item 9
Item 10
Item 11
Item 12

align-content: flex-end;

Item 1
Item 2
Item 3
Item 4
Item 5
Item 6
Item 7
Item 8
Item 9
Item 10
Item 11
Item 12

align-content: space-between;

Item 1
Item 2
Item 3
Item 4
Item 5
Item 6
Item 7
Item 8
Item 9
Item 10
Item 11
Item 12

align-content: space-around;

Item 1
Item 2
Item 3
Item 4
Item 5
Item 6
Item 7
Item 8
Item 9
Item 10
Item 11
Item 12

align-content: space-evenly;

Item 1
Item 2
Item 3
Item 4
Item 5
Item 6
Item 7
Item 8
Item 9
Item 10
Item 11
Item 12
css
/*aligns the items on the left edge*/
.container {
    justify-content: flex-start;
}
/*centres the items*/
.container {
    justify-content: center;
}
/*aligns the items on the right edge*/
.container {
    justify-content: flex-end;
}
/*spreads the items evenly between the
left and right edges with no space at the
edges*/
.container {
    justify-content: space-between;
}
/*spreads the items evenly between the left
and right edges with the same amount of space at
both edges*/
.container {
    justify-content: space-around;
}
/* spreads the items evenly between the left
and right edges with the same amount of space at both
edges and between each item */
.container {
    justify-content: space-evenly;
}

order

The order property sets the display order of the items in a flex container. It takes an integer, and the default value is 0.

1
2
3
4
5
html
<div class="container">
    <div class="item first">1</div>
    <div class="item second">2</div>
    <div class="item third">3</div>
    <div class="item fourth">4</div>
    <div class="item fifth">5</div>
</div>
css
.container {
    display: flex;
}
/*puts item 1 first*/
.first {
    order: -1;
}
/*puts item 3 second*/
.third {
    order: 2;
}
/*puts item 5 last*/
.fifth {
    order: 3;
}

With this code, the items are displayed in the order: 1, 3, 2, 4, 5

Every item that has an order value is sorted by that value, and items without one fall back to 0. Items with negative values are displayed before items with positive ones.

Play with these values until you get the layout you want. Note that the order in which the CSS properties are declared in the file has no effect on the display order: order is the only thing that controls it.

flex-grow, flex-shrink and flex-basis

The flex-grow, flex-shrink and flex-basis properties set the size of the items in a flex container.

  • flex-grow sets the share of the available space each item should take.
  • flex-shrink sets how much an item should shrink to fit into a smaller container.
  • flex-basis sets the base size of an item, before flex-grow and flex-shrink come into play.

flex-grow: 1;

flex-grow: 1;
2
3
4
5

flex-shrink: 1;

shrink
grow
grow
grow
grow

flex-basis: 200px;

flex-basis: 200px;
2
3
4
5
css
/* makes the item take up
all the available space */
.item {
    flex-grow: 1;
}

/* makes the item shrink
to fit a smaller container */
.item {
    flex-shrink: 1;
}

/* sets a base size of 200px for an item */
.item {
    flex-basis: 200px;
}

You can combine the three with the flex shorthand

css
/* flex: flex-grow | flex-shrink | flex-basi */
.item {
    flex: 1 1 200px;
}

Examples

Example 1: a grid built with Flexbox

1
2
3
4
5
6
7
8
9
html
<div class="container-flex">
  <div class="item-flex item1">1</div>
  <div class="item-flex item2">2</div>
  <div class="item-flex item3">3</div>
  <div class="item-flex item4">4</div>
  <div class="item-flex item5">5</div>
  <div class="item-flex item6">6</div>
  <div class="item-flex item7">7</div>
  <div class="item-flex item8">8</div>
  <div class="item-flex item9">9</div>
</div>
css
.container-flex {
  display: flex;
  flex-wrap: wrap;
  /* lets the items be spread over
  several lines when there is not enough room */
  justify-content: space-between;
  /* spreads the items evenly
  between the left and right edges with no space
  at the edges */
  align-content: space-between;
  /* spreads the lines evenly between
  the top and the bottom with no space at the edges */
}
.item-flex {
  text-align: center;
  flex: 1 0 calc(33.33% - 20px);
  /* uses flex-grow and flex-basis to spread the
  items over a 3-column grid using
  33.33% of the available width and
  20px less space between each item */
}

The flex property decides how items adapt to the space available in the flex container. Here we use flex: 1 0 calc(33.33% - 20px); to lay the items out on a three-column grid, each item taking 33.33% of the available width minus the 20px of space between items. The result is a responsive grid that follows the size of the window on its own.

Combine justify-content, align-content and flex and you can build flexible, adaptive layouts for whatever your page needs. These properties mix in many different ways, so experiment until you find the combination that fits your project.

Example 2: a responsive menu

html
<nav class="menu-container">
  <a href="#" class="menu-item">Home</a>
  <a href="#" class="menu-item">About</a>
  <a href="#" class="menu-item">Services</a>
  <a href="#" class="menu-item">Contact</a>
</nav>
css
.menu-container {
  display: flex; /* turns on the flex layout */
  justify-content: space-between; /* pushes the menu items to the right and to the left */
  align-items: center; /* centres the menu items vertically */
}

/* Adds a menu button for small screens */
.menu-container::before {
  content: "Menu"; /* Text shown on the button */
  display: none; /* hides the button by default */
}

/* When the screen is narrower than 600px */
@media (max-width: 600px) {
  .menu-container {
    flex-wrap: wrap; /* Lets the items wrap onto several lines */
    justify-content: center; /* Centres the items horizontally */
  }
  .menu-item {
    flex-basis: 100%; /* Takes the full available width */
    text-align: center; /* Centres the text */
  }
  .menu-container::before {
    display: block; /* Shows the menu button */
  }
}

In this example the menu is laid out horizontally, pushed to the left and to the right on wider screens (the default). On small screens (under 600px wide) the items are centred and wrap onto several lines, and a “Menu” button appears to open and close the menu with JavaScript or the tool of your choice. If you want a more detailed example of a Flexbox menu, I wrote a whole article on the subject.

Conclusion

The CSS Flexbox module makes flexible, adaptive layouts for your HTML elements straightforward. Properties such as display, justify-content, align-items and flex let you align and organise the items of a flex container efficiently.

Flexbox is particularly good for content grids, menus and responsive forms, because it hands out the available space according to what the layout actually needs. It is no cure-all for every layout problem, but it solves plenty of common ones. It is often used alongside other layout technologies such as Grid Layout, or layout frameworks such as Bootstrap.

Flexbox is a powerful tool for web developers building flexible, adaptive layouts for websites and applications. Understanding its properties and its basic uses is what gets the most out of it. And check the browser support limits before you ship it in a project.

That compatibility can be automated at build time: PostCSS adds vendor prefixes from the browser list you target. The setup is covered in the Webpack 5 guide, along with the last 2 versions trap, which drags Internet Explorer back in and bloats your CSS with dead prefixes.

CSS

Damien Flandrin Web developer since 2010, creator of Gekkode and Email Impact. Every article is tested on a real project before publication. Contact
Newsletter

New tests, tutorials and projects, by e-mail.

Reproducible tests, versioned code, dated results. Never any spam.