Category Archives: Layout

Multi-column confusion

tl;dr: Be careful when using multi-column layout.

Today I was finishing up a small portion of a project which involves generating PDFs with a multi-column layout from web content. Since we’re using the Prince formatter for the PDFs, there are no worries there, as Prince is one of the finest rendering engines out there, especially for this kind of thing.

But since I also created a live preview so the client can see their text in the intended layout while typing, I tested in some major desktop browsers. I was in in for a big surprise.

For anyone familiar with CSS Multi-column layout, the spec says basically—if I understand it correctly—that if no height is specified on the element containing the text columns, then the text should be distributed amongst these columns so that they are of (roughly) equal height. The value for this behavior is balance. If a height is specified, then the browser should use the value of the column-fill property, if it has been specified. If there is no column-fill property, then the browser should still balance the columns. Go ahead and read that again. I’ll wait.

I had set a height on my container. So I was confused about the fact that Chrome/Safari and Firefox were applying auto where they should have been applying balance.

A column-fill value of auto means that the browser should fill the columns in sequence, starting with the first column and filling it, then column two, etc. until there is no remaining text. The browser can do this because it knows the height of the column container. So the spec makes perfect sense, but I was scratching my head at this point. I had specified a height, but not column-fill. Every browser should have used balance, but only Opera did.

Well, I’m thinking it’s me, then I’m thinking it’s not me, so I tweet about it. Fellow CSS layout fan (and author of The Book of CSS3) Peter Gasston and I started chatting about it and tonight we jumped on GTalk and starting testing. Turns out the answer is quite simple: Peter starts off by telling me how Firefox and the Webkit browsers haven’t fully implemented the spec yet. I should have known that, but I didn’t, like an idiot. And it’s logical because the spec is obviously not finished yet.

But even after knowing that, it’s still pretty confusing, because which behavior conforms to the spec right now and which doesn’t? What’s supposed to happen when? I mapped my tests out in the form of two small comparison tables. They might look confusing, but they really aren’t. It’s pretty easy to figure out what you’d need to do to get either balance or auto. Even when the spec is implemented, it’s still useful to know under what conditions each of these values will be acted upon.

Multi-column column-fill defaults, when column-fill is not explicitly specified.
  Opera Firefox Chrome/Safari
No explicit height on container balance balance balance
Explicit height on container balance auto * auto *
Multi-column column-fill behavior when column-fill property is explicitly specified.
  Opera Firefox Chrome/Safari
column-fill: balance;
(container height specified)
balance auto * auto *
column-fill: balance;
(No container height specified)
balance balance balance
column-fill: auto;
(container height specified)
auto auto auto
column-fill: auto;
(No container height specified)
balance balance balance

As far as Peter and I can tell, the only behavior which does not conform to the spec is marked in red and with an asterisk. The rest seems (to me) to conform to the spec.

Again, I’ve run into this kind of thing because I’m knowingly using a spec which is not fully implemented. If you do the same, please realize that things can go wrong, and that you’re basically working with a work-in-progress. It might change, and you might have to change your code in the future. If you do use Multi-column now, please use it as a progressive enhancement. And don’t forget to use all the necessary vendor prefixes so that we all may live in peace and harmony.

As always, have fun!

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.

It’s okay to do adaptive layout. Really.

Vasilis wrote yesterday about how he altered the layout of the Tropenmuseum website (English homepage) to adapt to different screen sizes.

Then came the comments. Nothing really wrong with any of them, but the whole “layout is not the only thing that should concern you; performance/context/content/blah is also (maybe even more important)” thing is getting very tired. Why? Because nobody is saying those things aren’t important.

Here’s a fact: If the homepage of site [x] is 100kB, then it’s 100kB. If I make that page look decent on several devices via adaptive layout—unless I go overboard—it is still going to be 100kB. Okay, maybe 101kB. It’s either zoom hell or not. So people can complain about that, but unless they’re willing to add to the client’s budget, the extra layout flexibility is (often, not always) a relatively quick readability and usability win. Device-agnosticism should be baked into the design approach anyway. There’s absolutely no harm in it.

So no, do not ignore content strategy and performance. And if you do content strategy, then you’d do well to be thinking about design. Device-agnostic design applies here as well.

Don’t feel bad about doing adaptive layout just because these other things are also important. It’s okay. Really.