Learn You a Flexbox for Great Good!

This article is outdated and no longer accurate. Find up-to-date information about flexbox at HTML5 Please.

Yet Another Note (2012-05-13): It might be obvious that the flexbox spec is changing often, but a kind commenter suggested I add a note here regarding the fact that in the spec, the flex() function has been replaced by the `flex` property, which makes plenty of stuff in this article obsolete. Also, expect more to change. I will most likely leave this article as is. I will write an update as soon as I see an implementation in at least one more browser. As of this note’s date, Chrome still supports the version described below. —Stephen

Note (2012-05-12): I have added -moz-, -ms- and -o- vendor prefixes to all code examples and the demo. Here’s why. The spec is—at the time of this note—still in flux, so I intentionally left out the non-prefixed properties/values.

So you want to learn Flexbox? Perhaps you’ve heard about it. Perhaps you’ve read a tutorial or two about it. Perhaps you’ve even played around with it already.

If you’ve never heard of Flexbox, or if it’s been awhile since you’ve used it, forget what you know. We’re starting over! The spec has been rewritten; the last version at the time of this writing is dated 29 November 2011!

What you’ll need

CurrentlyAt the time of this writing, Chrome Canary Google Chrome has a partial implementation of the spec. If you’d like to follow along, you’ll need nothing more than Chrome Canary Google Chrome and your favorite text editor.

Ready? Let’s get to it!

What is Flexbox?

Flexbox is a nickname for CSS Flexible Box Layout Module. It’s one of a few CSS Working Drafts having to do with visual layout. Flexbox offers us a new box model which has been optimized for laying out user interfaces. In short: the children of a “box” can be ordered either vertically or horizontally within their parent, and we can control what happens to any remaining space. It is possible to nest these boxes, allowing for very complex layouts.

Caution!

There are other CSS layout modules in development which, in my opinion, are much more suited to general page layout than Flexbox. Flexbox is fairly straightforward, but can become unruly when used for complex layouts. In any case it is not the best solution for all types of layout. But for UI-components like buttons, forms, toolbars or rows and columns of content/media blocks for which you’d normally use floats, Flexbox makes code simpler and is a huge time-saver. Flexbox is designed to play nicely with existing CSS properties. Thus, you are still free to use floats or other types of positioning on non-Flexbox elements.

Three Little Boxes

If you’re feeling a bit lazy, you’re welcome to simply download and edit the demo page Otherwise…

Open your editor, create a simple HTML document with a single box. In this case, we’ll use a div:

Great, But it would be nice to see something, so we’ll have to add some style:


Now we’ll put three boxes into our div. These are, of course, the first div‘s children:

A
B
C

Let’s style those as well:


    div>div {
        width: 100px;
        height: 100px;
        background-color: pink;
    }

Now look at this page in Canarythe browser. Nothing unusual here, just three block-level elements one under another, as block-level elements are known to do. But we’ll put a stop to that. We’ve created our own Flexbox playground, so let’s play.

Defining a flexbox

We would like to apply the magic of Flexbox to the children of our parent div. We do so with the display property. By applying display: flexbox; to our parent div, we tell it to use the Flexbox box model. If we wanted our parent div to be inline instead of block-level, we’d use display: inline-flexbox;.


    body>div {
        display: -webkit-flexbox; /* We need the prefixes for now, unfortunately. */
        display: -moz-flexbox;
        display: -ms-flexbox;
        display: -o-flexbox;
        height: 500px;
        padding: 1em;
        background-color: gray;
    }

Our three child divs, which we’ll call flexbox items from now on, now live according to the Flexbox box model. Beware: there are rules that determine what a flexbox item is. For example, if we were to use position: absolute; on one of the three boxes, it would no longer be a flexbox item since we’ve applied a different positioning model. Read more about flexbox items in the spec.

Back to our little exercise. Take a look at the page in your browser. The flexbox items look a bit as if we had applied inline, inline-block or float to them. This is because the Flexbox default is to position flexbox items horizontally. The main difference so far is that we have only added a rule to the parent and not to the items themselves.

Source-order independence

Flexible Box Layout Module gets its name from the fact that it allows us to create flexible boxes. In other words, boxes can become flexible by utilizing available space. We’ll get to that in a minute. But Flexbox offers something at least equally important to us, especially in this Age of Mobile: source-order independence. Let’s play around and see how we can change the order of flexbox items.


    body>div {
        display: -webkit-flexbox;
        display: -moz-flexbox;
        display: -ms-flexbox;
        display: -o-flexbox; 
        -webkit-flex-flow: row-reverse;
        -moz-flex-flow: row-reverse;
        -ms-flex-flow: row-reverse;
        -o-flex-flow: row-reverse;
        height: 500px;
        padding: 1em;
        background-color: gray;
    }

OMG. Our flexbox items are now right-aligned and the order is reversed! We do this with the flex-flow property, for which row is the default value. row-reverse flips this around. You might have already guessed that when you want to position flexbox items vertically, you would use column or column-reverse. At the time of this writing, CanaryChrome does not support column-reverse, but try out column and see what happens! When you’re done playing around, set the value back to row and we’re ready for our next step.

By the way, flex-flow also takes a value for wrapping flexbox items to new rows (or columns, depending on which you’re using). The values wrap and wrap-reverse serve this purpose, as the default is a single row (or column) of flexbox items which overflows the parent. wrap and wrap-reverse still haven’t been implemented at the time of this writing (I’m saying that a lot). But let’s say, just for fun, that we could use wrap today:


    body>div {
        display: -webkit-flexbox; 
        display: -moz-flexbox;
        display: -ms-flexbox;
        display: -o-flexbox;
        -webkit-flex-flow: row wrap; /* `wrap` gives us a multi-line flexbox. */
        -moz-flex-flow: row wrap;
        -ms-flex-flow: row wrap;
        -o-flex-flow: row wrap;
        height: 500px;
        padding: 1em;
        background-color: gray;
    }

Mirror, mirror…

All the properties dealing with order, direction or alignment of flexbox items are influenced by the current writing mode. The writing mode is the original direction of the text. Many of us are used to top-to-bottom, left-to-right. But as soon as these are changed, the output of the directional Flexbox properties will also change. You’ve already seen what row-reverse does. But what if your writing mode isn’t the default (top-to-bottom, left-to-right) but top-to-bottom, right-to-left? Your flexbox items would be laid out from right-to-left in the first place, and row-reverse would flip things so they’re left-to-right.

Try it out:


    body>div {
        display: -webkit-flexbox; 
        display: -moz-flexbox;
        display: -ms-flexbox;
        display: -o-flexbox;
        direction: rtl; /* The `writing-mode` property currently has no visual effect in Chrome. The `direction` property will suffice for our example. */
        -webkit-flex-flow: row;
        -moz-flex-flow: row;
        -ms-flex-flow: row;
        -o-flex-flow: row;
        height: 500px;
        padding: 1em;
        background-color: gray;
    }

Look at the page in your browser. Now replace row with row-reverse. See what happens?

Confusing? Perhaps a little at first, but the properties all work logically based on the current writing mode. As most of us usually work with the same writing mode most of the time, it shouldn’t be much of a problem.

In order to understand the effect many Flexbox properties have on flexbox items, it is important to understand what the main axis and the cross axis are. The main axis is the axis along which the flexbox items are placed. In other words, if the flexbox items have been placed horizontally (flex-flow: row;), then the main axis is horizontal. The cross axis is perpendicular to the main axis. In our example, that would be vertical. When using flex-flow: column;, this is switched: the main axis is vertical and the cross axis is horizontal.

That’s a pain to explain well. Just to be sure we’re clear, here’s an illustration:

When items are horizontally positioned, the main axis is horizontal.

Remember main axis and cross axis, because we’ll need them in a bit.

Order! Order in the court!

Let’s look at another property which helps the cause for source-order independence: flex-order.

In your example code, make sure you’ve set flex-flow to row and have removed direction: rtl;. If things are as they should be, you’ll have three flexbox items: A, B and C, in the top left of body>div. Imagine that although our code contains these items in that order, that we want to display them in the order A-C-B. To do this, we’ll use flex-order:


    div:nth-child(2) { /* Yes, I could have used an ID or a class. But, hey, whatever. */
        -webkit-flex-order: 1;
        -moz-flex-order: 1;
        -ms-flex-order: 1;
        -o-flex-order: 1;
    }

Check things out in your browser. The order of the flexbox items should be A-C-B.

flex-order places flexbox items into ordered groups. Boxes without an explicit flex-order are in group 0 and remain in source order. In our example, the second flexbox item (B) is placed in group 1. A and C remain in group 0 and in source order (A before C). Since group 1 comes after group 0, the B comes last. If we had wanted the order B-A-C, we could have left B in group 0 and put A and C into group 1:


    div>div:first-child,
    div>div:last-child {
        -webkit-flex-order: 1;
        -moz-flex-order: 1;
        -ms-flex-order: 1;
        -o-flex-order: 1;
    }

Flexibility

One of the nicest aspects of Flexbox is the ability to create flexible elements. We can decide what to do with any remaining space in our body>div (in this example). We can divide this space up between the flexbox items, or we can make the widths or heights of one or more of these items flexible, alotting a certain amount of available space to each.

We’ll look at flexibility first and then come back to distributing available space.

Imagine that our three flexbox items are buttons in a web application which might also be used on mobile devices. Sometimes we have three, but sometimes we only have two (just nod and go along with it). We’d like to say, “No matter how many of these buttons there are, I want them all to generally be the same width, and these widths should be such that the row of buttons takes up all the available width of the parent.” We’d normally resort to JavaScript for these types of layout problems, but Flexbox might put an end to that. See what happens when we make our flexbox items flexible with the flex() function:


    div>div {
        /* width: 100px; */
        width: -webkit-flex(1 0 100px);
        width: -moz-flex(1 0 100px);
        width: -ms-flex(1 0 100px);
        width: -o-flex(1 0 100px);
        height: 100px;
        background-color: pink;
    }

The flex() function can be used as a value for width or height. flex() takes three values: positive flex, negative flex and preferred size. The last two parameters are optional; the default for negative flex is 0 and the default for preferred size is 0px. Here’s how flex() works in a nutshell:

  1. The preferred width is applied to the flexbox items.
  2. If there is any space left over in the parent, this space is divided up into parts and added to the widths of the flexbox items according to the positive flex value.
  3. If the flexbox items overflow the parent (e.g. together they are wider than the parent), then the negative flex value is used for determining the widths of the items. Please note that negative flex is a positive value (e.g. 2 and not -2).

A positive flex value of 1 basically means “one equal part of the available space”. A value of two would mean something like “twice the amount of available space as the items that have flex(1)”. So it’s nothing like “two parts whiskey, one part cola”. The easiest way to learn it is to try it out. Type the following code under your rules for div>div:


    div>div:first-child,
    div>div:last-child {
        width: -webkit-flex(2);
        width: -moz-flex(2);
        width: -ms-flex(2);
        width: -o-flex(2);
        background-color: magenta; /* This allows us to see the difference clearly. Plus, it hurts your eyes. */
    }

If you check your browser, you’ll see that the first and the last flexbox items don’t each have 2 parts of the available space. Rather, they have two times as much available space as the middle box, which has flex(1). I know, I know. Just be glad you’re not a browser maker. Unless you are, in which case: have fun and please get this implemented ASAP!

Also, please note that this does not mean that the two outermost boxes are two times as wide as the center box. We’re only dealing with how the available space in the parent is being distributed.

Remove the declaration you just added. Remove one of the divs and look at the result in your browser. Once you’ve seen what happens, put the div back in again.

There’s plenty more about flex() and any other gory details you might want to know about Flexbox; these can all be found in the spec.

Alignment of flexbox items

Did you remember everything about main axis and cross axis? Excellent. Because the flex-pack property determines how flexbox items are aligned along the main axis. In our example file, the main axis is horizontal. In order to study the effect of flex-pack, remove flex() and change the width back to 100px:


    div>div {
        width: 100px;
        height: 100px;
        background-color: pink;
    }

flex-pack accepts one of four possible values: start, end, justify and center. Pretty clear. Let’s center our flexbox items. We do this on the parent:


    body>div {
        display: -webkit-flexbox;
        display: -moz-flexbox;
        display: -ms-flexbox;
        display: -o-flexbox;
        -webkit-flex-flow: row;
        -moz-flex-flow: row;
        -ms-flex-flow: row;
        -o-flex-flow: row;
        -webkit-flex-pack: center; /* 

Go ahead and play with the other values until you like it.

Of course, there is a property for aligning flexbox items along the cross axis: flex-align. The possible values differ slightly from flex-pack. The most important thing to remember is that while flex-pack is applied to the parent of the flexbox items, flex-align is applied to the flexbox items themselves.


    div>div {
        width: 100px;
        height: 100px;
        background-color: pink;
        -webkit-flex-align: center; /* Also: start | end | baseline | stretch  

Not all the values are supported yet, but I don’t think we’ll need to wait very long. As the spec solidifies, implementation should come fairly quickly. The browser makers are quite interested in Flexbox.

Enough! Time to play

There are a couple of other properties having to do with multi-line flexboxes, but since we can’t try those out yet, we’ll stop here for now. Hopefully we’ve handled enough material to get you started playing around with the “new” Flexbox. Try and consider practical applications. How could Flexbox help within the context of “responsive design” and mobile? What possibilities open up for form styling? Navigation?

You don’t need to be able to use this today in actual projects to learn and experiment with the possibilities. Implementation might come quicker than you think, and you’ll already have a head start.

Have fun!

Note: This article first appeared in the Dutch language for the Fronteers Advent Calendar. Payment for the article was a modest donation to ICCF Holland.

23 thoughts on “Learn You a Flexbox for Great Good!

  1. This is a great tutorial overall. However, a major failing is that the demo has only a single character in each box, which has the great problem of perpetuating the most major misunderstanding of flexbox: that the flex property applies the extra space relative to the width of the container, rather than the intrinsic/default widths of the boxes themselves. Your text explains it correctly (thank you! everyone gets this wrong!) but the demo doesn’t make this clear because each box has the same amount of content and thus same intrinsic width.

    A much more helpful, realistic demo would have varying amounts of content in each box so that they each have different intrinsic widths. Readers would then see that the first and last boxes aren’t necessarily twice as wide as the middle box. This is something that’s essential for us all to understand. It even took me by surprise when I was researching it and writing about it in my book Stunning CSS3. The spec isn’t intuitive here, unfortunately.

  2. @Zoe: Relatively few things are a major failing, and using letters in a demo certainly isn’t one of them. This is not boilerplate code.

    I really don’t understand your explanation within the context of the newest version of the spec. Are we talking about the same thing? This post is based on the draft per 29 November 2011; I doubt that is the version you researched for your book.

    I suspect that the confusion here is related to the issue Niloy refers to in his comment, which is actually a non-issue.

    I hope you’re describing the older version of the spec, as your explanation does fit with that one. If you are referring to the version I’ve written about here, perhaps you could clarify what you mean for the readers of this post. Intrinsic width is not once mentioned in the new spec, so your discussion of it might be confusing to some.

    I appreciate your feedback.

  3. Flexbox has changed so frequently and it is not supported by main browsers. How can the new mobile device support it…

  4. It is expected that the latest version of Modernizr should detect this new spec of flexbox…..is there any javascript library to mimic this new spec….? would it degrade gracefully to its previous spec?

  5. If offers nice features indeed, thank you for such thorough exmplanation!

    But who knows when we’ll be able to rely on such layouts when building real-world web sites and web-apps? I mean those that require cross-browser support down to some crappy IE8-. As even all modern up to date browsers currently don’t support it.
    And developing separate layouts for modern browsers and for old ones seems a waste of time now, when we can use well tested and quite reliable old-school solutions based on floats, position and js tests.

    An interesting thing is that when I tried to make a few tests according to this article, flex() function didn’t work at the latest Chrome Canary (20.0.1116.0), but worked at current stable build of Chrome (18.0.1025.162).

  6. I don’t see where implementing the flex() “value” is difficult.
    You just have to total all the positive flexes of the elements in the flexbox and divide the left space by this. Now just add this value multiplied by the positive flex to the element’s width.
    In (pseudo)code:
    width = preferred_width + (left_space / sum_of_positive_flexes) * positive_flex;
    For negative flex it’s the same, you just have to use the length of the overflow instead of the left space and of course you have to subtract it from the preferred width:
    width = preferred_width – (overflow_length / sum_of_negative_flexes) * negative_flex;

  7. Great writeup, just the flex() function was removed in the latest spec, so please consider adding a note to the top of the article, or updating it (yay, like for the 3rd time… I know… but flexbox is awesome though and deserves the attention!)

  8. What is the point? You can already achieve these layouts using a table. How does flexbox help you create a row of labelled buttons such that every button has the same width (the width of the button with the widest label).

  9. Randy, even though I’m yet sceptical about the feature due to low support at the time, there is really the point and even not one point. At least, table is a more rigid structure and this is semantically ‘table’ and flex-flow gives more control over semantics and on the elements layout, for example elements order, alignment.
    You should check http://www.w3.org/TR/css3-flexbox/#flex-items for more obvious samples and explanations.

  10. Great article, thank you so much for explaining this, it make sense now! I’m working on a redesign of my companies website (Ground up, it’s so much fun…), and I’m wondering this: Is there a way to achieve relatively the same results (redefining when the browser window shrinks, wrapping, fluidity) using a technique that would be supported by browsers other than Chrome? Because that’s all my code works on right now…

  11. @Adam: Yeah. Don’t use this on a production site. The article is meant to inform, but as I noted at the top, the spec keeps changing. Until we get Flexbox, the best way to do things right now is fluid grids using the tools we have available (positioning and floats, basically), and to do so responsively when possible. flexie.js tries to implement Flexbox cross-browser with JavaScript, but it uses the old syntax and I would strongly advise against making JavaScript-dependent layouts.

  12. I wasn’t planning on having it go on as the production site, just considering what I could do with it, as it seemed the like the best way to do what I wanted. I have only been coding for about a week, so I’m not entirely sure what I’m doing. Could you possibly point me towards a tutorial for what you were talking about, or an explanation? Thanks!

  13. @Adam: You’ve just started developing? Well then, welcome to the coolest job ever :)

    If you did just start developing, I’d say forget Flexbox for now and start with the basics. You can’t go wrong with two of the best web development documentation repositories around:

    To learn more about responsive design specifically, I refer you to the original article.

    In this field, you’ll never stop learning. Have fun with it and good luck!

  14. Is it possible to use flexbox to allow for flexible height in the same way it does for width? So all boxes within the parent would be the same height? This, I think, would be more useful than flexible width.

    CSS hacks and JS seems just unnecessary and annoying for something that should be so simple.

  15. It might be worth mentioning Lea Verou’s prefixfree.js at this point, which is extremely useful in adding straightforward css that would otherwise be a multiplicity of vendor-prefixes. This could help you clean up your examples even more. http://leaverou.github.com/prefixfree/

Comments are closed.