Requirements

Prerequisite knowledge

HTML, CSS and some knowledge of new CSS3 features

 

Additional required other products

User level

All

Flexible layouts. Equal height columns. Presentation independence from your HTML source order. These things haven't been so easy to achieve with CSS—until now. The flexible box layout, the new flexbox specification, makes creating any of these layouts easy, and much more.
 
In this article I'll walk you through the latest flexbox specification and use a simple demo to show you how to create a layout that's flexible, and has equal height columns and elements that you can arrange in any order, regardless of their order in the HTML source.
 

 
About browser support

There is some bad news with regard to flexbox and browser support. While most current browsers support flexbox, there have been several versions of the specification. The problem is that not all browsers support the latest version. The following explains which browsers support the most recent flexbox specification:
 
  • Opera (12.1) - Supports the latest specification without the need for vendor prefixes.
  • Chrome (23.0) - Supports the latest specification, but requires the -webkit vendor prefix.
  • Safari (5.1) - Supports an older version of the specification with the -webkit vendor prefix.
  • Internet Explorer (10) - Supports an older version of the specification with the -ms vendor prefix. Internet Explorer 9 and below does not support it.
  • Firefox (16.0) - Supports an older version of the specification with the -moz vendor prefix, however once version 20.0 arrives, Firefox will support the latest specification without vendor prefixes.
The following explains which mobile devices support the most recent flexbox specification:
 
  • iOS and Android support an older version of the specification but requires the -webkit prefix.
  • Blackberry (with version 10) supports the latest specification but requires the –webkit prefix
  • Opera mini offers no support.
In other words only two browsers support the current version of the specification, which is what this article uses. One browser will support the current version soon, and most of the other browsers and mobile devices support an older version of the specification.
 
Note: As of this article, keep in mind that the current specification only works with recent versions of Chrome and Opera. Since these are the only browsers that support the latest specification, the example CSS won't include any vendor prefixes beyond -webkit.
 
For more information, go to W3C website.
 
Figure 1. Flex direction terminology.
Figure 1. Flex direction terminology.

 
The flexible box layout model

CSS operates under several types of layout models. You've certainly worked with elements using the block, inline, table, and positioned layout models before.
 
The flexible box is another layout model. In a flexbox there are two axes, a main axis and a cross axis. The main axis is the primary axis and cross axis runs perpendicular to the main axis. Each axis has a dimension associated with it and each axis has a start and end point. Items within the container and the container itself have a size based on their associated width and height. You can see all of terms defined in Figure 1.
 

 
How to create a Flexbox

The easiest way to understand how flexbox works is to see it in action. To do that, I've set up a simple demo with the following HTML inside the body of an HTML document. The widest screens will have a three-column layout with the HTML. The smallest screens will flow in a single column. In between will be a two-column layout.
 
 <div class="flex-container">     <div class="header"><p>Header</p></div>     <div class="content"><p>Main Content</p></div>     <div class="sidebar primary"><p>Primary Sidebar</p></div>     <div class="sidebar secondary"><p>Secondary Sidebar</p></div>     <div class="footer"><p>Footer</p></div> </div>
As you can see above, we have a single flex-container div tag, which you can probably guess will become the flex container. The five inner div tags (header, footer, main content, and two sidebars) will be the flex items.
 
Not shown is a bit of lorem ipsum inside the main content and primary sidebar div tags. I’ve also set up some generic base styles to give each div tag a background color, padding, and text color so that we can tell them apart easily. See the file base.css in the sample file ZIP downloaded (flexbox.zip).
 
To create a flexbox, simply set the display property of the container to one of two values.
 
.flex-container {display: flex;} .flex-container {display: inline-flex;}
The first creates a block level flexbox and the second creates an inline level flexbox. For the demo sample, create a block level flexbox within the CSS, as follows:
 
.flex-container {     display: -webkit-flex;     display: flex; }
This displays as follows.
 
Figure 2. Layout with flexible container and flex items.
Figure 2. Layout with flexible container and flex items.
With this code, we've created a flexbox, though by default it's not very exciting. All the elements inside the flexbox are now flex-items, and they flow one after another as though they've all been floated to the left, which is somewhat interesting—as we haven't floated them. This brings us to the flex-direction property.
 
Note: Chris Coyier has an excellent writeup on mixing the old, new, and in-between specifications to make flexbox work in as many browsers as possible. Again, I'll only be talking about the latest specification in this post, but here's how one could expand the above code on the .flex-container div to target more browsers.
 
.flex-container {   display: -webkit-box;      /* OLD - iOS 6-, Safari 3.1-6 */   display: -moz-box;         /* OLD - Firefox 19- (buggy but mostly works) */   display: -ms-flexbox;     /* TWEENER - IE 10 */   display: -webkit-flex;     /* NEW - Chrome */   display: flex;                /* NEW, Spec - Opera 12.1, Firefox 20+ */ }
You can read Chris' post, Using Flexbox: Mixing Old and New for the Best Browser Support for more details.
 
 
Ordering and orienting
The reason the flex-items currently fall one after the other has to do with the flex-direction property. This property sets the direction of the main axis of the flexbox. There are four possible values.
 
  • row (the default)
  • row-reverse
  • column
  • column-reverse
Since we haven't set a value, we get the default row. A value of row-reverse flips everything horizontally. In this case, the header would start at the far right and then each of the other divs would be placed to the left of the one before, as though they were all floated to the right.
 
Setting the flex-direction to column sets the start of the flexbox to the top and each div will fall one below the other. A value of column-reverse starts the flexbox at the bottom of the container, with each flex item sitting on top of the one that came before.
 
Another property you'll likely set along with flex-direction is flex-wrap. This sets whether the container is a single-line flexbox or a multiple-line flexbox. It has the following possible values:
 
  • nowrap
  • wrap
  • wrap-reverse
You can set these properties with a single shortcut property, flex-flow. When setting flex-flow, you set the flex-direction followed by flex-wrap. In the demo, I set the flex-flow property as follows:
 
.flex-container {     -webkit-flex-flow: row wrap;                flex-flow: row wrap; }
I mentioned flexbox helps us break free of source order. If you've been working with responsive design you know that when your layout is a single column, the boxes sit one on top of another in the same order structured in your HTML. That can be limiting depending on what your design calls for when the layout expands to multiple columns.
 
Flexbox removes this limitation with the order property. Set the order property on flex items to define the order in which to display the items. This property takes integer values. In the demo I haven't done anything exciting yet with the order of the flex-items, but feel free to play around. In our sample, we’ll change the order of these elements in a bit, but for now they're set to reflect the same order they appear in the source.
 
.header                   {-webkit-order: 1;} .content                  {-webkit-order: 2;} .primary                  {-webkit-order: 3;} .secondary                {-webkit-order: 4;} .footer                   {-webkit-order: 5;}
To see what we’ve accomplished so far, see the screenshot on my site.
 
At this point I've probably convinced you that flexbox is pointless, since the layout looks exactly the same with or without it. Let's change that so you can see how easy flexbox makes it to change layouts.
 
With our default layout all the divs display in a single column. That's fine for a phone, but what if you wanted to change the display a little for a screen that is a bit wider? Once the screen is at least 48em wide, what if you wanted the main content and primary sidebar to display as two columns, one next to the other? What if you wanted to change the order so that the primary sidebar comes before the main content. The following modifications do just that:
 
@media screen and (min-width: 48em) {     .content {         width: 67%;         -webkit-order: 3;     }                         .primary {         width: 33%;         -webkit-order: 2;     } }
Notice how easy that was to change the layout. Simply adjust the widths of each div so they can fit together on a single row. Then, change the order so that the sidebar displays first.
 
To see what the demo looks like with this new layout, see it on my site.
 
The changes were so simple, you may have missed it. Do you realize what happened without having to do anything? The height of the sidebar column matches the height of the main content column. We didn't have to do anything to make that happen. Add more paragraphs to the main content. Remove some. Add enough list items so the sidebar becomes longer. It doesn't matter. The columns will always be equal height because of the flexbox.
 
This is not bad at all. A few simple lines of code to overcome the limitations of having to structure HTML with a particular source order, and equal height columns render by default.
 
Figure 3. Flexbox with a two-column layout and reverse HTML source order.
Figure 3. Flexbox with a two-column layout and reverse HTML source order.
Let's bring the other sidebar into this and expand the layout to three columns. While we’re at it, let's move the primary sidebar all the way to right, after the secondary sidebar.
 
@media screen and (min-width: 60em) {     .content {         width: 50%;         -webkit-order: 2;         order: 2;     }     .primary {         -webkit-order: 4;         order: 4;     }     .secondary {         -webkit-order: 3;         order: 3;     }     .sidebar {         width: 25%;     } }
To see what the demo looks like with this new layout, see it on my site.
 
Again what we’ve done is pretty easy. I adjusted the width so that everything fits on a single row and changed the order of the flex-items. Hopefully you can see how easy it is to rearrange a layout with a few lines of code. And once again, there are equal height columns for free.
 
Figure 4. Flexbox with a three-column layout and altered HTML source order.
Figure 4. Flexbox with a three-column layout and altered HTML source order.
There are a few more concepts to flexboxes. Let's expand the demo so we can talk about them.
 

 
How flex items flex

One of the benefits of flexboxes is that as the container grows or shrinks, the items inside can also grow or shrink, while still maintaining their same proportions. Even better is that you don't have to specify a size of any kind. The flex items will size themselves to fill the box. You can use the following properties and a shorthand to set this up.
 
  • flex-grow – Specifies how much a Flex item can grow relative to other flex items (integer value)
  • flex-shrink – Specifies how much a Flex item can shrink relative to other flex items (integer value)
  • flex-basis – Specifies the initial main size of the Flex item before free space is distributed (value is width or auto)
  • flex shorthand - none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
To see the flexboxes in action, I removed the text from the content div and replaced it with three new divs: Box 1, Box 2, and Box 3. The following shows the new HTML minus some lorem ipsum inside the primary sidebar.
 
Figure 5. Flexbox inside a flexbox
<div class="flex-container">   <div class="header"><p>Header</p></div>   <div class="content flex-content">     <div class="box box1"><p>Box 1</p></div>     <div class="box box2"><p>Box 2</p></div>     <div class="box box3"><p>Box 3</p></div>   </div>   <div class="sidebar primary"><p>Primary Sidebar</p></div>   <div class="sidebar secondary"><p>Secondary Sidebar</p></div>   <div class="footer"><p>Footer</p></div> </div>
I set the content div to be its own flexbox, so there is now one flexbox inside another. This time I set the direction to column. Since you must set a height for this container, I arbitrarily set it to 30em.
 
.content {     display: -webkit-flex;     display: flex;     -webkit-flex-flow: column wrap;             flex-flow: column wrap;     height: 30em; }
The three boxes each get a background color and the flex-grow property, as follows:
 
.box1 {     background: #933;     -webkit-flex-grow: 8;             flex-grow: 8; } .box2 {     background: #393;     -webkit-flex-grow: 1;             flex-grow: 1; } .box3 {     background: #339;     -webkit-flex-grow: 3;             flex-grow: 3; }
After making this change, you will see that without any measurements, the three boxes grow to fill the space according to the relative proportion set above. Box 1 is eight times the size of Box 2, and Box 3 is three times the size of Box 2.
 
To see the results of this demo at this point, go to my site.
 
Next, to switch to a two-column layout, change the size and order of the boxes.
 
@media screen and (min-width: 48em) {     .box1 {         -webkit-flex-grow: 6;                 flex-grow: 6;         -webkit-order: 1;                 order: 1;     }     .box2 {         -webkit-order: 3;                 order: 3;     }     .box3 {         -webkit-flex-grow: 1;                 flex-grow: 1;         -webkit-order: 2;                 order: 2;     } }
To see demo at this point, see my site.
 
Figure 6. Two flexboxes with the inside flexbox rearranged
Figure 6. Two flexboxes with the inside flexbox rearranged
Once we have enough room for three columns, let's change the boxes again, this time having Box 1 take up one row with the other two boxes sharing a row below it. First we'll change the flex-flow property for .content to render as a row and then set box1 to have a width of 100%.
 
@media screen and (min-width: 60em) {     .content {         -webkit-flex-flow: row wrap;                 flex-flow: row wrap;     }     .box1{         width: 100%;     }     .box3 {         -webkit-flex-grow: 2;                 flex-grow: 2;         -webkit-order: 3;                 order: 3;     } }
To see the demo at this point, see my site.
 
Once again, you can make significant changes to the layout with just a few lines of CSS. It might not initially seem all that impressive, but for perspective, think about what you would have to do with JavaScript and perhaps jQuery to achieve the same changes without using flexbox.
 
Figure 7. 3 columun flexbox with mixed column inside flexbox
Figure 7. 3 columun flexbox with mixed column inside flexbox

 
Aligning Flex items

So far we've had Flex items fill the container without needing to specify  dimensions. Sometimes  the items in a flex container require a width and height dimensions. For example the items might all be images of a fixed size that must display in a grid.
 
Let's adjust the demo once more. I've removed the flex-grow values from the three boxes and instead set them all to have the same width and height, as follows.
 
.box {     width: 25%;     height: 5em; }
If you make this change, you’ll see that the boxes no longer fill the container and instead start at the top and sit one below another. That's because the direction of the flex container is set to column. Suppose you would like the boxes to be distributed inside the container in another way. There are several properties that you can use to do just that.
 
You can align elements along the main axis of the container with the justify-content property, which you assign to the flex container with the following values.
 
  • flex-start - Packed toward start
  • flex-end - Packed toward end
  • center - Packed toward center
  • space-between - Evenly distributed in line
  • space-around - Evenly distributed in line with half-size spaces at ends
Along the cross axis we have two similar properties.
 
  • align-items - Set on the container, it becomes the default setting for all Flex items
  • align-self - Set on the items, it overrides align-items for that specific Flex item
Both use the same flex-start, flex-end, and center as justify-content and they work the same way, except that they act in the cross direction. However, the properties space-around and space-between are replaced with the following values, each with it's own set of context-driven rules.
 
  • baseline - Aligns the baseline of flex items to the cross line
  • stretch - Stretches items a little to align Flex items and baseline
Both have some detailed rules of how they work, which you can find here, though experimenting with them will probably help you understand them better.
 
I’ve set up one last demo to show these properties. I set a space-between value on justify-content and a value of center to align-items . I added these values to the content div.
 
.content {   -webkit-justify-content: space-between;               justify-content: space-between;   -webkit-align-items: center;               align-items: center;
I’ve overridden the align-items value on two of the boxes with the align-item property.
 
.box1 {   -webkit-align-self: baseline;               align-self: baseline; } .box3 {   -webkit-align-self: flex-end;               align-self: flex-end; }
To see the results of this last demo, see my site.
 
My values are arbitrary. I encourage you to play around with the different values and explore what you can do.
 
Figure 8. Aligning flex items within a fixed container
Figure 8. Aligning flex items within a fixed container

 
Where to go from here

Hopefully I’ve shown you how easy flexbox is to work with and even more how “flexible” it truly is. After playing around with flexbox for an hour or so you'll probably be chomping at the bit for browsers to properly support it so that you can start using it in production.
 
Of the five major desktop browsers, the current version of flexbox already works in two, with one more on the way. One other (Safari) will likely get the latest specification before too long, since the work is already in webkit. As for Internet Explorer support, you're probably used to dealing with older versions of it by now and there are flexbox polyfills, like Flexie for example, that you can use.
 
Unfortunately flexbox isn't quite prime-time ready just yet, but it does get closer all the time. If you’re willing to mix the old, new, and in between specifications you can support most browsers.
 
Now that the specification has settled, I think we'll reach the point soon where all current browsers support the latest specification in some fashion (possibly with vendor prefixes). We’ll just need consider how far back we need to support Internet Explorer or if we want to use a polyfill.