CSS offers several tools to help with site layout. Over the years we’ve worked mainly with floats, positioning, and margins, but let’s face it, most of us would like more. Fortunately css3 is giving us more tools for layouts. One of those tools is the flexible box.
Note: This post refers to an older and out of date version of the flexbox spec. A more recent post that refers to an up to date version of flexbox can be found here.
A couple of weeks ago .net magazine published an article on The future of css layouts, in which they covered several new css3 layout modules. I’d like to work through some of them starting today with the flexible box layout module.
I’ve created a demo page illustrating some of the properties of the flexbox, though there’s not much to see in the demo that you can’t see from the images throughout this post. It’s there in case you want to play around with the source code.
Browser Support
There’s actually pretty good support for flexible boxes in the latest browsers. Safari, Chrome, Firefox, and IE10PP all support everything discussed below.
On the other hand Opera as well as IE9 and below don’t support it so the flexible box isn’t yet ready for full time use unless you’re ok adding a javascript solution. Flexie is one such solution, though I haven’t had a chance to test it.
You should also know that the spec is changing. The latest W3C working draft and editor’s draft use different terminology than what currently works in practice. I’ll stick with the terminology that currently works and make note of the corresponding terms in the latest specs.
Also note that I’ll stick with the generic terminology in this post, but to make flexible boxes work in practice you’ll need to use vendor prefixes like -webkit and -moz.
Creating a Flexbox
CSS 2.1 defined 4 layout modes
- block — for overall layout
- inline — for text
- table — for tabular data
- positioned — for explicit positioning
Flexbox is a new layout mode provided by css3 and it’s similar to block layout on the surface. It lacks some properties of blocks such as floats and columns, but it adds some simple tools for aligning content inside a box.
In a flexbox content can be laid out in any direction, elements can be reordered dynamically, and the size and position of elements can flex in response to the available space.
A flexbox will act like a block when placed it other layout modes by default, but it can be set to act as an inline-box as well. Child elements of a flexbox are referred to as flexbox items.
Here’s a simple example of how it will work.
{code type=html}
{/code}
Above we have a parent div with two child divs. The parent div will become the flexbox and the child divs will be the flexbox items inside the flexbox.
{code type=css}
#flexbox {display: box; width: 600px}
#box1 {width: 300px}
#box2 {width: 150px}
{/code}
Pretty simple to set up and again you need to use vendor prefixes at the moment.
- display: -webkit-box
- display: -moz-box
You’ll notice that horizontally we have 150px extra of space inside of the flexbox. Properties we later set on the flexbox items will allows us to modify this extra space and alter the behavior of the flexbox.
Note: In the current specs flexbox is being used instead of box so in time we’ll use display: flexbox.
Note 2: Once again the flexbox spec has changed and instead of either box or flexbox, it now calls for flex as in display: flex and flex-{*} for other properties.
box-orient and box-direction
box-orient sets the direction in which flexbox items will be laid out inside the flexbox and has several allowable values
- horizontal — Lay out children from left to right in a horizontal line
- vertical — Lay out children from top to bottom vertically
- inline-axis — Lay out children along the inline axis (map to horizontal)
- block-axis — Lay out children along the block axis (map to vertical)
- inherit — The value will be inherited from the parent element
In the image above I set box-orient to vertical, which is probably the value you’ll set most often. Horizontal is the default.
box-direction is a more general way to set the order of the flexbox items. The one value to know about is reverse which displays the flexbox items in reverse order of how they’re listed in the html.
Note: It looks like both box-orient and box-direction are becoming the single flex-direction in the current working drafts.
flex-direction will have the associated values lr, rl, tb, bt, inline, inline-reverse, block, and block-reverse. lr stands for left to right and tb stands for top to bottom.
box-pack and box-align
We won’t always want to fill up all the extra space inside a flexbox. We may instead prefer to have child elements positioned within that space, for example centered vertically or horizontally.
One property we can use is box-pack, which has associated values of start, end, center, and justify.
Start and end can ultimately be any of the 4 box sides depending on whether your flexbox is horizontal or vertical and which direction it’s items are laid out in.
{code type=css}
.box {box-pack: center}
.box {box-align: center}
{/code}
Assuming a horizontal flexbox with no reverse set, start refers to the left edge and end refers to the right edge.
Items would be packed against this edge with the next item packed against the first. Center packs things toward the center and justify packs toward the edges.
Another property for dealing with extra space is the box-align property. It’s values are start, end, center, and stretch, which work similarly to the same values for box-pack.
A new value here is baseline which says to set each flexbox item so their baselines align and then distribute the space above and below. The baseline can be either horizontal or vertical depending on the direction of the flexbox.
Note: The current spec refers to box-pack as flex-pack and box-align and flex-align.
box-lines
The box-lines property sets how the box handles content that overflows it’s size and has the associated values single and multiple.
- single — All child elements will be placed in a single row or column (elements that do not fit will simply be considered overflow)
- multiple — The box is allowed to expand to multiple lines, to accommodate all of its children
Note: box-lines aren’t mentioned in the most recent spec, but the editors draft refers to flex-flow, which looks to mimic box-lines. I also haven’t been able to get box-lines working in any browser I’ve tested in.
Flexbox Items
The properties above control how the flexbox itself behaves. We also have some properties to control how the flexbox items behave.
Only direct descendants of the flexbox are considered flexbox items. Children of flexbox items (grandchildren of the flexbox) are not also flexbox items of the same flexbox.
A new flexbox would need to be created for them to become new items of a new flexbox.
box-ordinal-group
box-ordinal-group controls the order in which the flex-items are displayed within the flexbox. The values of the box-ordinal-group property are integers.
{code type=html}
span2
span3
span4
{/code}
Above we have 4 spans inside a div. Below we’ll set the div to be a flexbox and assign a box-ordinal-group to some of the spans.
{code type=css}
div { display: flexbox; }
#span1 { box-ordinal-group: 2; }
#span3 { box-ordinal-group: 2; }
#span4 { box-ordinal-group: 1; }
{/code}
Because span 4 is given a box-ordinal-group of 1 it will display before both spans 1 and 3, which have a box-ordinal-group of 2.
Span 2 doesn’t have a box-ordinal-group specified and so defaults to a box-ordinal-group of 1. Because span 2 appears in the html before span 4 and because both have the same box-ordinal-group, span 2 will display first.
The order the spans will be displayed is
- span2
- span4
- span1
- span3
This will solve a lot of the problems I talked about last week in regards to rearranging html boxes as we’ll have more control over the order the boxes are displayed.
Note: In the latest specs box-ordinal-group is being referred to as flex-order, though it will work the same way.
box-flex
box-flex sets whether or not the child items are inflexible or flexible and in the case of the latter, how. It tells the flexbox and flexbox items what to do with the extra space.
It’s values should be seen as fractions. An element with a box-flex of 2 would get twice the extra space as an element with a box-flex of 1.
{code type=html}
{/code}
The above html is the same example used at the start of this post.
{code type=css}
#flexbox {display: box; width:600px}
#box1 {width:150px; box-flex: 1}
#box2 {width:150px; box-flex: 13}
#box3 {width:150px; box-flex: 1}
{/code}
Again we have 150px of extra space inside the box. Here we’ve set box-flex values of 1, 13, and 1 respectively on our flexbox items.
The center flexbox item will receive an additional 130px of the extra space and the other items will each receive 10px of the additional space.
Another property, box-flex-group, is meant to group flexbox items. However at the moment it has no browser support and no mention in the latest spec.
Note: The latest working draft makes no mention of box-flex or box-flex group. Both seem to be absorbed into the flex() function, though the syntax of flex() is still under discussion.
Additional Resources
Below are some other articles that cover the flexible box layout module. They discuss the same properties as I have here and offer their own examples of the code in use.
- The CSS 3 Flexible Box Model
- Quick hits with the Flexible Box Model
- Introducing the Flexible Box Layout module
- CSS3 Flexbox
- The CSS3 Flexible Box Layout (flexbox)
Summary
The Flexible box layout module adds a lot tools to control the boxes you create in your layouts. Hopefully you can see how much flexibility it truly adds.
There’s more support for flexboxes than you might think as long as you stick with a terminology from the 2009 spec. Do note that the terminology is changing, though it shouldn’t be hard to transition to it.
There’s probably not enough support to use flexboxes in practice, though of course it depends on what browsers you need to support.
The good news is flexbox seems to be coming in the next version of IE. The bad news is we’ll have to wait for enough people to upgrade or use a Javascript workaround. I suspect Opera will get on board soon enough.
Download a free sample from my book, Design Fundamentals.
Thanks for the tutorials!
This seems interesting, but I will not use it simply for this reason:
“The latest W3C working draft and editor’s draft use different terminology than what currently works in practice.”
Anything in such an early stage of development should not be used in any real situation. Sure, fun to play around with, but I’ll wait until it’s finalized to learn and use it.
I’m not sure that flexbox is ready for prime time yet either, but it’s closer than many things.
The difference between the current working draft and the editors draft are minimal. We’re talking display: box to display: flexbox. Most of the other differences are similar
I wouldn’t let those kind of changes stop you. A few quick search and replaces would be enough to fix things and there’s no way to know for certain when browsers would make the switch to any new terminology.
Also consider that you could still code a layout that won’t break if flexbox stops working. It would depend on where and how you use it. One application for flexbox is vertical and horizontal centering. Should your flexbox code stop working that probably doesn’t break the layout.
At the same time I’d agree it’s probably not the thing to use for client sites just yet. I wanted to explore a few things that are on the way, though, hence this post.
really nice knowing new box system, I have been playing with sencha touch layout for a while an there are layout features like this in sencha touch, I bet it adopting from this CSS flexbox
I’m not familiar with sencha touch layout. What does it do?
Great article Steven!
There are bugs registered for the box-lines property for both Firefox and Webkit. Please vote on them if they’re important to you.
https://bugs.webkit.org/show_bug.cgi?id=38426
https://bugzilla.mozilla.org/show_bug.cgi?id=562073
IE10 seems to implement -ms-box-lines so I wonder what will happen to flex-flow.
Thanks Matias. I appreciate the links to the bugs.
I’m not sure what the standards will ultimately be. I assume it’ll be what’s in the more recent spec even though it’s not what’s currently working.
Regardless I’m pretty excited about flexbox. It can solve a few issues I seem to run into often enough.
Right now, as of today, do you think we should do layouts this way? If so, why? Also, fallbacks, with Javascript, fine, but it could be done via IE conditional statements, no? Also does Opera support this or not? Furthermore, I heard that the draft or syntax is quite different. Do you think we ought to go for it and change it once it has been (or add it in this case).
I wouldn’t say we should use flexbox yet. I think it could be used, but at the moment there are the drawbacks you mentioned.
Opera and IE lack support, though you can take care of that with Javascript. I don’t think conditional comments would work since you’re layout would be very different for IE. You could try, but I think that would be too hard to work with. The spec is changing, though the difference in syntax isn’t hard to understand as I showed in the post.
For all those reasons I wouldn’t use flexbox just yet. I think you can use it if you don’t mind the workarounds, but for production sites it’s probably best to wait a little longer.
Having said that it wouldn’t surprise me if their are sites already using it.
I think I am going to steer away from it until Opera supports it.
Why Opera? Because if I am doing the site in HTML5 I still need Javascript for it to display for older IE browsers, so we have a saying here that goes, “if you are going to **** it up, do it all the way til the end”.
If the user has JS disabled, the site will not recognize the elements and wll look bad anyway. If he does, then the JS solution will work for both styling purposes and the flex-box model.
With Opera you need browser support in case someone has JS disabled.
IE 9.0 DOES support it, right?
I think your decision makes sense. I really want to use it, but for now I think we’re better off waiting a bit more. I don’t worry so much about JS being disabled though. Many workarounds for css3 and html5 tend to be specifically for older versions of IE. I think the percentage of people with IE6 or IE7 and JS disabled is small enough to ignore, particularly for any site that deals with something technical.
As far as I know IE9 does not support flexbox by default. Only IE10PP seems to have built in support. You’ll need a workaround for IE9 and below.
Okay, thought IE9 had support for it. Thanks a lot Steven!!
Why not make a small php/js script that will show IE/opera compatibly layout, and use flex-box for moz and webkit?
As a general rule I don’t think it’s a good idea to use Javascript for layout.