In August, due to a twitter discussion with Molly, and of course while partying on a Saturday night, Dave Gregory and I were looking at whether the Flexible box layout module (still a working draft) is getting close to ready for prime time yet. Our hope was that it will solve some of the frustrations we have with layout—like columns that are equal heights and vertical centering. We read the spec and some good articles. It gave us hope. We started testing on our own. That’s when we realized how much is left to do here.
First, I’ll say that both webkit- and moz-based browsers did great in our simple testing of four equal-sized boxes—whose background colors fill each container. They were they equal width, and the color filled the container whether the content did or not. Good news! There is a difference in the height of the containers between -webkit and -moz which is related to their differing treatment of the bottom margin on the paragraph inside each box. I don’t know which one is right, but find it odd that when Webkit allows the margin to escape, it doesn’t push the next element away as can happen in a floated/non-floated layout. (But that’ll be another experiment.)
The demos shown on the Mozilla site appear to work, but in real life really don’t yet work as expected.The demos work because there’s not really content in the boxes—and in that situation, the flex box does work. But check our tests to create four equal boxes with content—especially content that varies in length. Less than wonderful.
On vacation (when else is there time!?), I was reading Zoe Gillenwater’s excellent book, Stunning CSS3. If you want a well-written, easy to understand, beautiful book on the new CSS3 capabilities, I highly recommend this one. Anyway, the last chapter of the book is about upcoming layout possibilities—most of which covers the flexible box model. It got me thinking about my earlier testing. I started playing around with having widths on one or more of the boxes. These results didn’t really do what I expected.
If I give three of the boxes a width, with one set to box-flex:1, it will fill the remaining space. It doesn’t seem to matter how much content is in them.
This seems to be the most reliable way to use the flexible box layout right now—to take up remaining space.
I then, bravely, placed box-flex:1 on two of the four boxes. This, as I read the spec, should have added up the widths of the two boxes where the width property exists and then equally divide what is left over between the two flexible boxes. If I had set one box to a value of 2 and the other to 1, it should divide it into thirds, giving 2/3 to the box with a value of 2. Instead, we went back to unreliability. The boxes don’t split the space left evenly, they seem to split it based on their content. This may be the way it should work, and I may be misunderstanding the spec, but it seems very unreliable as a form of layout.
- Two box-flex and two with widths (the widths are correct)
- Two box-flex which are not next to each other with the same results
Finally, I gave the first and last boxes pixel widths. The middle two both had box-flex:1. They have substantially different amounts of content. The larger literally suffocates the smaller amount of content—even though they should be splitting it more evenly as I read it.
- The second box is overflowing its boundaries even though each line is a single word—causing the page to be much taller than it should.
- A small increase in content made it slightly wider and the page is closer to the height it should be.
I’m playing with this and don’t feel I’m the definitive expert. But I do think something is far from correct in browser implementations—or the spec needs to be much more clear. Either the boxes should be split evenly, or they should be split so that they’re the same height, but widths are based on content within (though that’s not what I think I read in the spec). Currently, the odd splitting, based on content, but not even at all, is baffling me.
Update: Based on Zoe’s comment, I did a few more tests. If widths are given to all boxes and then box-flex is added to one (or more), the dividing of space between the boxes is reliable. It seems to be when you leave the browser to use the intrinsic width as a default that unmatched content amounts gives you extremely unreliable results.
- Equally sized boxes with 1 box-flex — extra 200px left in container
- Equally sized boxes with 1 box-flex — overage of 200px
- Equally sized boxes with 2 box-flex:1 — extra 200px left in container
- Equally sized boxes with 2 box-flex — one set to 1 and the other 2
Opera hasn’t implemented flexible boxes yet (they’re reportedly waiting for a more complete spec) and though this may be included in Internet Explorer 9, as you might expect it’s certainly not in any of the earlier versions. (Update: It appears it’s not made it into the RC which is feature complete.)
Once this is implemented more fully, it’s going to be a very interesting new weapon for the arsenal. Kinda makes you wish someone working on CSS3 had realized our lack of proper layout is more important than making things move around and transform—we already have Javascript for that anyway.
{ 8 comments… read them below or add one }
Actually, the browsers are right to make the widths unequal. That’s how the spec says box-flex should work. It doesn’t specify the ratio of the widths, it specifies the ratio of the extra space assigned to each. It’s confusing and non-intuitive (I’ve never seen a single article on box-flex get it right) but that’s what’s in the spec. Bummer, huh? I explain it on pages 248-250 in Stunning CSS3. There’s currently no way to make the boxes equal in width, or set one to be twice as wide as the other, etc.
@Zoe – Yea, as I mentioned above, I read it. That’s what brought me back to my August sandbox. I guess it’s the “intrinsic width” thing that’s throwing me since I keep reading that they should split any space overage (or underage) evenly or based on their ratio that you set. What I WANT them to do is split the space evenly. But clearly they split that space based on how much content is in each to start with—which means a CMS could kill your layout. To compound the confusion, most demos don’t really use much content (especially differing amounts). But it’s when content is added that things get wonky.
I just added a couple more tests which I’ll add as an update above using widths on ALL boxes. Clearly, using box-flex works as long as a width is already defined. So it just keeps the layout from breaking due to something like float drop for the most part. It’s getting clearer.
It’s become very apparent that the “start the flexing from the content-size” model that the current Flexbox draft uses, while useful (it’s necessary to implement Firefox’s UI, for example), is not intuitive as the default behavior.
In the current draft, the way to get more intuitive flexing behavior, where everything with the same box-flex becomes the same width, is to set width:0 on them first. I dunno how well this works in webkit, but it should work in Firefox.
I’m nearly done with my substantial rewrite of the flexbox draft, and will publish a new Editor’s Draft (and hopefully a Working Draft soon afterwards) in the next week. The basic mechanics are the same, but the syntax should produce better default results and be easier to understand. For example, most of your examples will be done by just setting the container to “display:flexbox” and then the children to “width: flex(1);”, and then they’ll work as you expect. No need to have a separate property tell you how the width is *really* calculated, with the “width” property just being an input to that process. You can also flex margins and paddings in my new draft.
Regarding your final comment, “better layout managers” is one of my top priorities in the CSS working group. Block layout is fine for documents, but has been unacceptable for website or application layout for *years*. Table layout helped somewhat, but not enough. In the next few years we’ll gain at least 3 new layout managers which are much better suited to the needs of pages and apps – Flexbox Layout will be the first, followed soon after by Grid Alignment (an iteration on the older Template Layout) and Positioned Layout (beefier position:absolute powers, so you can actually put together a good reactive layout with it). The future will be an exciting place. ^_^
Tab, you don’t know how happy you just made me.
The changes sound really good. The current behavior of flexbox definitely has its uses, but not nearly as many (in my work, anyway) as the more intuitive behavior of making widths relative to each other, rather than making additions/subtractions from inherent width relative to each other.
The preview versions of IE 9 have support for flexbox (or the one I last checked did) with the -ms prefix, but it has never made it into the beta. Sounds like this is a good thing with all the changes on the horizon.
> Based on Zoe’s comment, I did a few more tests. If widths are given
> to all boxes and then box-flex is added to one (or more), the dividing
> of space between the boxes is reliable
That doesn’t work perfectly. If you try this trick on your “varied content” example, by adding {width: 0} to .hbox div, you’ll notice that the first column is still larger than its siblings. Better, but still not reliable.
One real issue with the flexible box model as it currently stands is how Firefox deals with widths defined in percentages. It appears that if child elements widths are defined as a percentage and the parent container is given the ‘display:box;’ attribute, the width attribute is simply ignored on the children. Setting the ‘box-flex’ attribute to 0 or 1 has no effect at all. Chrome and Safari work as desired either if the width of the child element is set to ’0′ and ‘box-flex’ is 1 or the width is ’50%’ regardless of the value of ‘box-flex’. For this reason, at this time, the flexible box model is just not practical to use on a site that needs to work across all major browsers.
Apparently if you set an arbitrarily large width (i.e. 9999px) in addition to box-flex it works (going off Tab Atkins’ comment I tried 0 width but that didn’t work but then I tried increasing it and they became even again independent of the content). It seems to work in firefox and chrome/webkit.
{ 6 trackbacks }