Learn You a Flexbox for Great Good!

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

Currently, Chrome Canary has a partial implementation of the spec. If you’d like to follow along, you’ll need nothing more than Chrome Canary 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:


    <!DOCTYPE html>
    <html lang="en">
        <head>
             <meta charset="utf-8">
             <title>Flexbox</title>
        </head>
        <body>
            <div>
            </div>
        </body>
    </html>

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


    <style>
        body>div {
            height: 500px;
            padding: 1em;
            background-color: gray;
        }
    </style>

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


    <div>
        <div>A</div>
        <div>B</div>
        <div>C</div>
    </div>

Let’s style those as well:


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

Now look at this page in Canary. 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 prefix for now, unfortunately. */
        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; 
        -webkit-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, Canary 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; 
        -webkit-flex-flow: row wrap; /* `wrap` gives us a multi-line flexbox. */
        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; 
        direction: rtl; /* The `writing-mode` property currently has no visual effect in Canary. The `direction` property will suffice for our example. */
        -webkit-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;
    }

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;
    }

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);
        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);
        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; 
        -webkit-flex-flow: row;
        -webkit-flex-pack: center; /* <-- */
        height: 500px;
        padding: 1em;
        background-color: gray;
    }

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  <-- Try these vales as well! */
    }

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.

OMG A Blog Post

When David Storey commented that I should change my company’s name from Zero Interface to Zero Blogging, I knew I had to write something very soon. The truth is, while I’ve been traversing mountains of client work, doing some speaking engagements and becoming a father (again), I actually have been doing some writing. Only not for this blog. I refer you to the November 2011 issue of .net Magazine, where I wrote an overview of the new galaxy that is Responsive Web Design. For the readers who know Dutch, I refer you to the Fronteers Advent Calendar, for which I wrote an introduction to the new, improved Flexbox spec, which due to some demand I will most likely translate to English and publish here.

See what I did there, David?