With a lot of talk recently over at Mozilla about supporting the Flexbox specification in the near future (in its current iteration anyway), I thought it would be good to cover exactly what the CSS3 Flexible Box Specification can do, and how it’s really going to simplify layout design, as well as changing forever how we do it.
Support
Support for this specification is surprisingly good, with both Webkit and Trident (Internet Explorer) supporting at least some parts of the specification. There are no up to date polyfills at the moment, so we’ll just have to use what’s already implemented in browsers.
Webkit | Gecko | Trident | Presto | |
flex | Canary | Soon (Maybe) | None | None |
flex-align | Platform Preview | |||
flex-item-align | None | |||
flex-direction | ||||
flex-flow | Platform Preview | |||
flex-line-pack | ||||
flex-order | ||||
flex-pack | ||||
flex-wrap | None |
The slow pace of development in Trident means that webkit is our only real option for an up to date implementation of the flexible box specification.
How Flexible Boxes Work
So I bet now you’re wondering how exactly a flexible box layout works. Flexible boxes allow for divs to align beside each other (previously we used float: left;
), and also for divs to fill up the remaining space (instead of using percentages). It basically tackles two of the greatest problems when designing a layout.
First Steps
I’m using Google Chrome Canary and the editors draft of the specification. so we’re going largely by the specification as to what each means. The flex box works by first having a set of elements which are not positioned absolutely inside a container:
<div id="flexbox"> <div class="item1">DIV 1</div> <div class="item2">DIV 2</div> <div class="item3">DIV 3</div> <div class="item4">DIV 4</div> <div class="item5">DIV 5</div> </div>
Next we need to set the parent container to flex box mode. We do this via the display property. We can have an inline flexible box or just a regular block kind. For this tutorial we’re going to be using the regular block kind.
We can also define what way we want the boxes to align. We have two main options, column
and row
, as well as reverse-column
and reverse-row
. Then we can say whether or not the divs will wrap using flex-wrap
. We can set it to either wrap
or nowrap
(which means that line breaks will not occur when the maximum space is used up). So your CSS should look a little like this: (I’m using webkit specific properties since webkit has the best support)
#flexbox { display: -webkit-flex; -webkit-flex-flow: row; // Children elements will be in rows -webkit-flex-wrap: nowrap; width: 100%; }
The Properties
To understand how the flex box works in more detail, I’ve listed all the flex box properties and how they work.
flex
flex: [positive flex || negative flex || initial width];
The flex property determines how much a box can flex. There are 3 properties. The positive flex determines how much a box can increase in size. The negative flex determines by how much a box can shrink.
As an example, lets say you have a box that is 500 pixels wide with a bunch of divs inside it. The container div is set to act as a flexible box, but when they’re all lined up with have a gap of 100px! If we set the positive flex for one box as 2, and the positive flex for another box as 3, the first box will take up 2/5 of the extra area (that’s 40px) and the other box will take up 3/5. We get the 5 from adding up all the positive flex values.
The same thing will happen with negative flex, only the other way around (the boxes will shrink). Here’s an example, but for simple stretching you only need to define the positive flex (as in flex: 3
). There’s also an image example so you can visualize it.
flex: 2 1 40px;
flex-pack
flex-pack: start | end | center | justify | distribute;
Determines how the boxes are aligned horizontally within the container. If you choose start they will all appear on the left, end, they will all appear on the right, and center, they will all appear in the middle. Justify will make the boxes fill the parent element with gaps between them, and distribute will do the same, only leaving gams at either side.
flex-line-pack
flex-line-pack: start | end | center | justify | distribute | stretch;
This is the same as flex-pack, only for vertical boxes as opposed to horizontal. The key words do the same thing as you’d expect, only on boxes on top of each other.
flex-order
flex-order: <number>
This defines the order the elements appear in. This comes in very useful when creating a layout. As an example, you could set the first div to appear in the 4th position, that is to say, the first div will appear as the 4th div.
#flexbox div:first-of-type { -webkit-flex-order: 4; }
Layout Example
So lets say you want to create a layout using flexbox, and you have HTML that looks a little like this:
<div id="header"></div> <div id="content"></div> <div id="footer"></div>
We want the header to be at the top, footer at the bottom, with two fixed columns (the sidebars) and we want the main content to resize to fit. We can easily accomplish this using the flexible box model.
#header { background: purple; width: 100%; height: 200px; } #content { display: -webkit-flex; -webkit-flex-flow: row; width: 100%; } #content #left-sidebar { width: 200px; height: 300px; background: blue; } #content #right-sidebar { width: 200px; height: 300px; background: green; } #content #main-content { -webkit-flex: 1; background: #eee; } #footer { width: 100%; height: 200px; background: orange; }
Because we set the flex of the #main-content
to 1, the #main-content
div will resize to fill any empty space.
Conclusion
The flexible box CSS specification will certainly change how we make layouts in the near future. Things like floats will be a thing of the past, tied only to article content, rather than whole web designs, which in all honesty was a little unreasonable anyway. Even though support is pretty low on the ground (Webkit is exceptional, as usual), we can expect to see an increase quite soon.
Comments
Oh, that is very clever! Just spent a happy few minutes putting together a menu bar to test this. Brilliant.
“Gecko support: Soon (Maybe)”
Are you kidding me?
:)
Firefox has had this forever, it’s even documented on MDN and other places – https://developer.mozilla.org/en/CSS/-moz-box-flex
There are huge chunks of Firefox’s UI itself (and quite a lot of addons even) that use this technique extensively for layout:
.something {
display: -moz-box;
-moz-box-flex: 1;
-moz-box-orient: horizontal; /* or vertical */
}
See also -moz-box-pack, -moz-box-direction etc.
It is non-standard, so that’s why there are different implementations across different browsers. Webkit is not a standard.
Gecko doesn’t support the specification I covered in this tutorial. I thought it would be misleading to say it did. I didn’t even mention box-pack, so I thought it best to say support was non existant for the time being.
Looks awesome, any word on what the IE10 RTM support will look like?
Here is a full detailed explanation for compatibility including IE10+
http://www.wpmemorize.com/2013/css-flexbox-to-design-flexible-layouts/
Thanks a million for explaining the subtleties of the flex box spec.
hello, i use crossbrowser inline-block))
but it does not allow block content to resizing
I hope your method will soon pick up speed)
big up!
There may be some inconsistencies between the specification and implementation by browsers. These will eventually be fixed though!
This is just perfect. However when people will still use IE7 it is useless :(
Dear author,
I’m not sure if you’re aware of Opera’s recent decision of aliasing the -webkit prefixes of some CSS3 features. This is bad. But it’s not Opera’s fault, and it was a smart move. It was developer’s fault for not using the unprefixed CSS properties.
Part of the problem, it seems to me, is that most tutorials written explain and use the -webkit prefixes but NOT the default CSS3 values nor the other browser prefixes. Wether this is for convenience or plain lazyness, it’s a fact it confuses newcomers to CSS3. If you teach someone using ONLY the -webkit prefix, they’ll assume that’s how it’s done, and ignore the other prefixes. I know you mention support is great, and that you’re using webkit because it has the best support, but that’s no reason to ignore the other ones on the code samples.
Please, don’t spread this evil any more. Add the actual properties and other vendor’s prefixes to this tutorial for the future’s sake.
P.S. Great tutorial!
Great articles and great illustrations! The only problem is with the “distribute” ones — while the background color and the border/padding are of the same color it’s hard to see at the first glance that the space is equal everywhere.
Also, on the first illustration the `1 0` etc pairs look a bit like `10` etc.
Ah, and it would be great to see the link to the latest spec somewhere in the article too :)
Very detailed! and helpful, indeed!
Very nice explanation!
Firefox supports this functionality (with the -moz- prefix of course.)
http://hacks.mozilla.org/2010/04/the-css-3-flexible-box-model/
From the date of the published article, I guess gecko supported it from April 22, 2010?! —I don’t understand why is it marked soon under Gecko, in your graphic. (also I agree with you Enrique Ramírez.)
It could be a nice idea to include all available vendor prefixes along with the w3c recommendation when we publish tutorials on these new and exciting stuff! (even if they are not yet implemented by today’s browsers! After all that’s the standard right?!)
p.s. Great tutorial indeed! Thanks!
The implementation is based on old specification so the name of the feature is not flex, but box.
-webkit-box-orient: horizontal;
-moz-box-orient: horizontal;
box-orient: horizontal;
etc.
This is nice CSS feature.
So if you want columns, you use `flex-flow: row;` and if you want rows, you use `flex-flow: column;`? Who made that up?
Why is there no `flex-pack: stretch;`? How would you do that? I was kind of expecting a `width: *;` or something.
Oh btw. // doesn’t comment in CSS =)
Hello,
reverse-column and reverse-row are not supported by Chrome (20) but the specs values column-reverse and row-reverse are.
The last example should not use width but flex like this, tested on Chrome 21.0.1163.0 dev-m:
#content #left-sidebar {
-webkit-flex: 0 50px; // not width property here.
height: 300px;
background: blue;
}
#content #right-sidebar {
-webkit-flex: 0 50px; // not width property here.
height: 300px;
background: green;
}
I translated your post, btw. Hope you won’t angry with that.
Why do they do this to us?!
Just updated chrome to find out my old syntax (i.e. display: -webkit-box) no longer works. Awesome.
The W3C is a harsh mistress.
What is your take on Flexie.js? http://flexiejs.com/
I actually came across this plugin while looking for ways I could show people implementation of this in older browsers. Flexie is a great plugin, but it doesn’t support the latest specification which uses flex. Instead flexie uses the box syntax which is no longer what the specification outlines, and for that reason I don’t think it’s a good idea to use it.
Thanks for the demo, but unfortunately the specs have changed again. I’ve build a pretty extensive demo that showcases the different options and possibilities: http://codepen.io/anon/pen/purLy (needs Chrome Canary).
I am curious as well as interested in what you really are talking about below.
hello!,I really like your writing so so much! proportion we communicate more about your article on AOL?
I need an expert on this area to unravel my problem. Maybe that’s you! Taking a look ahead to peer you.
So this currently is only good for doing Android HTML 5 stuff ?
Because I don’t think this works on IE10, did someone gave it a try ? (Sorry I’m on Ubuntu, cannot test on this browser)
If anyone is interested in bumping this feature in Firefox, please ad yourself to the CC list of this enhancement bug:
https://bugzilla.mozilla.org/show_bug.cgi?id=702508
The more people vote, the more the developers will notice the need for this feature.
Your section on flex (positive flex, negative flex, initial width) which is followed with two rectangular blue diagrams for visualization, is *IMPOSSIBLE* to follow for someone who has no experience with flexbox.
Try re-reading your own words from the perspective of having no experience with it, and you’ll see.. At one point you explain that your container DIV contains “a bunch of divs inside it” and then you go on to explain one div has a pos flex of 2 and another has a pos flex of 3. So is the “bunch of divs” you’re referring to only 2 divs? That’s a couple, not a bunch. Read that from the perspective of someone who knows zero about the subject and you’ll find yourself wondering where the rest of the divs are, since he did say “a bunch” didn’t he? Later in the diagram you show a container with 3 divs inside it.. and none of them has a pos flex of 3. Didn’t he just talk about a pos flex of 3 and say that this diagram was to help visualize it? So where’s the div with the positive flex 3?
If you’re trying to teach or explain to people who have no experience, *all* of your diagrams and descriptions and code samples need to be absolutely clear and they need to line up with each other. Just because “you” understand it doesn’t mean your students do.
Hello Solomon,
First of all, I am not a teacher, I only present this information to web developers which may find it interesting. I do not intend to teach the basics of web design to everyone. Secondly, what I’ve said does make sense, in that there is a div with a bunch of divs inside it, and then I refer explicitly (as an example) to two divs which have a positive flex value applied to them, and how the space would be divided amongst them (in that the extra space would be given to the two divs with the positive flex values). I further clarify this by showing a diagram which shows precisely how the positive flex value works in practice. Studying this diagram, with the information given, I imagine should be sufficient for most to understand. I even clarify in the diagram that the extra space is split between the boxes. Furthermore, before the diagram you talk about, I say ‘Here’s an example’, implying that this is a new thing altogether, rather than connected to the previous statements. If you read what I’ve written correctly it should make sense to you.