Flexbox

Suppose I have a set of divs like so.

<div class="boxes">
  <div class="red box">1</div>
  <div class="green box">2</div>
  <div class="blue box">3</div>
</div>

If I want them to sit next to each other I could use float:left, though that can be annoying with the having to use clearfixes because it’s kind of a hack.

<style>
  .box { float: left; }
  .boxes::after {
    content: 'Hello I am a clearfix';
    clear: left;
    display: block;
  }
</style>

<div class="boxes">
  <div class="red box">1</div>
  <div class="blue box">2</div>
  <div class="green box">3</div>
</div>

Maybe it would be better if I used display:inline-block and pretend they’re inline elements (with a bit of font-size:0 to collapse whitespace)

<style>
  .boxes { font-size: 0; }
  .box {
    display: inline-block;
    font-size: 50px;
    vertical-align: bottom;
  }
</style>

<div class="boxes">
  <div class="red box">1</div>
  <div class="green box">2</div>
  <div class="blue box">3</div>
</div>

Or display:table; and display:table-cell; and pretend it’s an old-school table layout.

<style>
  .boxes { display: table; }
  .box { display: table-cell; }
</style>

<div class="boxes">
  <div class="red box">1</div>
  <div class="green box">2</div>
  <div class="blue box">3</div>
</div>

Move over

There is a new way. And the new way is flex-box. Behold!

All you need to do is give your wrapper element display:flex;.

<style>
  .boxes { display: flex; }
</style>

<div class="boxes">
  <div class="red box">1</div>
  <div class="green box">2</div>
  <div class="blue box">3</div>
</div>

Concepts

Flexbox is a new CSS display model (similar in scope to the block, inline, float, and table display models). It’s a part of the CSS spec, natively supported by all the latest versions of browsers.

Flex container

This is a outside block element that makes it all happen. It has display:flex or display:inline-flex. Everything happens because of this.

<style>
  .boxes {
    display: flex;
  }
</style>

<div class="boxes">
  Flex container
</div>

Flex item

All the immediate children of the flex container are flex items. (Child text nodes are automagically wrapped in an anonymous flex item.)

<style>
  .boxes {
    display: flex;
  }
</style>

<div class="boxes">
  <div class="red box">
    <div class="text">Flex item</div>
  </div>
  Text pretending to be a flex item.
</div>

Direction

Everything else in flexbox is defined relative to the flex direction, which is defined relative to the text direction of the current language (one of left-to-right, right-to-left, top-to-bottom, or bottom-to-top).

Reorder

Suppose I want to change the display order of elements, without affecting source order?

Set setting order:n; on each element will work.
The elements will be sorted by order value, with 0 as the default.
like z-index, order doesn’t require the numbers be sequential.

<style>
  .boxes { display: flex; }
  .red   { order: 99; }
  .green { order:  2; }
</style>

<div class="boxes">
  <div class="red box">1</div>
  <div class="blue box">2</div>
  <div class="green box">3</div>
</div>

look ma, no position:relative;

Direction

<style>
  .boxes {
    display: flex;
    flex-direction: column;
  }
</style>

<div class="boxes">
  <div class="red box">1</div>
  <div class="blue box">2</div>
  <div class="green box">3</div>
</div>

If you want the cells to be vertical then on the wrapping element you can set flex-direction:column; (the default value is row)

You can also set row-reverse or column-reverse which does what it says on the tin. These are relative to the text direction, so in an Arabic page the something with row will be look like row-reverse on an English page.

Alignment.

Perhaps we want our items centred. nightmarishly difficult, yes? no.

justify-content:center centres the elements along the flex-direction axis, while align-items:center works on the perpendicular axis:

align-items:center

<style>
  .boxes {
    height: 350px;
    display: flex;
    align-items: center;
  }
</style>

<div class="boxes">
  <div class="red box">1</div>
  <div class="green box">2</div>
  <div class="blue box">3</div>
</div>
<style>
  .boxes {
    height: 350px;
    display: flex;
    flex-direction: column;
    align-items: center;
  }
</style>

<div class="boxes">
  <div class="red box">1</div>
  <div class="green box">2</div>
  <div class="blue box">3</div>
</div>

justify-content:center;

<style>
  .boxes {
    height: 350px;
    display: flex;
    justify-content: center;
  }
</style>

<div class="boxes">
  <div class="red box">1</div>
  <div class="green box">2</div>
  <div class="blue box">3</div>
</div>
<style>
  .boxes {
    height: 350px;
    flex-direction: column;
    justify-content: center;
  }
</style>

<div class="boxes">
  <div class="red box">1</div>
  <div class="green box">2</div>
  <div class="blue box">3</div>
</div>

both!

<style>
  .boxes {
    height: 350px;
    display: flex;
    justify-content: center;
    align-items: center;
  }
</style>

<div class="boxes">
  <div class="red box">1</div>
  <div class="green box">2</div>
  <div class="blue box">3</div>
</div>
<style>
  .boxes {
    height: 350px;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
  }
</style>

<div class="boxes">
  <div class="red box">1</div>
  <div class="green box">2</div>
  <div class="blue box">3</div>
</div>

Wow. That’s so easy. How much of my life have I wasted fighting CSS to center things, even in this very blog layout? never again (except all the times I need backwards compatibility)

The other options are flex-start and flex-end which align to the left or top, or right or bottom of the row or column, whichever makes the most sense based on the current flow direction.

justify-content: also has the option to space-around and space-between which spreads out the elements evenly. (space-between ignores the space on the ends). Wow. So many easy. So many simple.

If you have wrapped lines, then use align-content instead of align-items.

It’s also possible to set align-self: on an flex-item to give it a different alignment than all the other things, I can’t see why you’d want this, but maybe you’re a special snowflake.

Flex

Ladies and gentlement, this is the moment you’ve all been waiting for.

Flex is shorthand for flex-grow flex-shrink flex-basis so I’ll tackle them individually.

flex-basis:[length] (default is 0px). The length is used along the flex-direction axis. It’s basically the same as setting height or width.

if flex-grow is set to 0 then it won’t ever grow. It will be at most the flex-basis size. The equivalent for flex-shrink works also.

<style>
  .boxes { display: flex; }
  .box {
    flex-grow: 0;
    flex-shrink: 0;
  }
  .red   { flex-basis:  70px; }
  .green { flex-basis: 140px; }
  .blue  { flex-basis: 210px; }
</style>

<div class="boxes">
  <div class="red box">1</div>
  <div class="green box">2</div>
  <div class="blue box">3</div>
</div>

If the container is bigger than all the items lengths, then the flex-grow value is taken into account. This value represents its share of the remaining space.

In this example each flex item’s flex-grow value matches the number shown, so box 1 grows to fill 1/6 of the available space, box 2 grows to fill 1/3 of the available space, and box 3 grows to fill the final half of the available space.

<style>
  .boxes { display: flex; }
  .box { flex-basis: 70px; }
  .red   { flex-grow: 1; }
  .green { flex-grow: 2; }
  .blue  { flex-grow: 3; }
</style>

<div class="boxes">
  <div class="red box">1</div>
  <div class="green box">2</div>
  <div class="blue box">3</div>
</div>

If the container is smaller than all the items lengths, then the flex-shrink value is taken into account. This value is how much length is taken off, relative to other flex items flex-shrink value, to fit the row (relative to the length to be removed overall, not the length of the item. I think).

<style>
  .boxes { display: flex; }
  .box { flex-basis: 50%; }

  .red   { flex-shrink: 1; }
  .green { flex-shrink: 2; }
  .blue  { flex-shrink: 3; }
</style>

<div class="boxes">
  <div class="red box">1</div>
  <div class="green box">2</div>
  <div class="blue box">3</div>
</div>

I haven’t got a grasp on the default values for flex yet, so I’ve been overly specific - the default value of the short-hand flex are different than the defaults for completely unspecified flex values.

Wrap

The last thing we will learn today, before you go to an amazing page of ideas which you’ll now know how to use is: flex-flow

With this you can control the wrapping of the flex items.

<style>
  .boxes {
    height: 350px;
    display: flex;
    flex-wrap: wrap;
    align-content: flex-start;
  }
</style>

<div class="boxes">
  <div class="red box">1</div>
  <div class="green box">2</div>
  <div class="blue box">3</div>
  <div class="purple box">4</div>
</div>
<style>
  .boxes {
    height: 350px;
    display: flex;
    align-content: flex-start;
    flex-wrap: wrap;
    flex-direction: column;

  }
</style>

<div class="boxes">
  <div class="red box">1</div>
  <div class="green box">2</div>
  <div class="blue box">3</div>
  <div class="purple box">4</div>
</div>

You can also wrap in the other direction with flex-wrap:wrap-reverse, and the other-other direction (with the help of flex-direction:*-reverse)

When wrapping is combined with the flex property, something magical happens.

<style>
  .boxes {
    height: 350px;
    display: flex;
    flex-wrap: wrap;
  }
  .box { flex-grow: 1; }
</style>

<div class="boxes">
  <div class="red box">1</div>
  <div class="green box">2</div>
  <div class="blue box">3</div>
  <div class="purple box">4</div>
</div>
<style>
  .boxes {
    height: 350px;
    display: flex;
    flex-wrap: wrap;
    flex-direction: column;
  }
  .box { flex-grow: 1; }
</style>

<div class="boxes">
  <div class="red box">1</div>
  <div class="green box">2</div>
  <div class="blue box">3</div>
  <div class="purple box">4</div>
</div>

That’s all we have time for, folks.

Look at Solved by flexbox for common design patterns that are simplified/solved by flexbox. Read MDN’s flexbox documentation for more details than I’ve given here.

You can play with flexbox yourself here.