Flexbox vertical ordering

The only times I've had cause to use flexbox in anger is for content re-ordering, or as Jordan Moore more eloquently puts it, content choreography. Even at that I've only ever used vertical re-ordering and that's all I'll be talking about in this post. Other more comprehensive resources are listed at the end.

A project I am currently working on is a large content site with gazillions of pages and sub pages. We decided to keep the main navigation simple (6 or so items) and display a list of sub pages in each category.

In smaller viewports the list is in a block just before the page footer and on larger viewports we decided to move it under the main navigation at the top of the page and visually tie it to its parent menu item using colour.

Demo one is a page with the basic markup and style that roughly reflects the project before flexbox is used, and for clarity I've left out the page header and footer.

From top to bottom it's:

  1. a div containing the main content block and a secondary block
  2. another secondary block
  3. the block containing the list of sub pages.

It's these three blocks that we'll be reordering using flexbox.

The web designer's web designer Chris Coyier recently wrote about the best way to get flexbox working in as many browsers as possible so we'll use that as the baseline for our vertical ordering.

The boxes that are to be re-ordered need to be wrapped in a container with the display set to flex.

.l-flex {
	display: -moz-box;
	display: -webkit-box;
	display: -webkit-flex;
	display: -ms-flexbox;
	display: flex;
}

The default display is horizontal so to change that we'll add the declarations to make it vertical.

.l-flex {
	display: -moz-box;
	display: -webkit-box;
	display: -webkit-flex;
	display: -ms-flexbox;
	display: flex;
	<b>-moz-box-orient: vertical;
	-webkit-box-orient: vertical;
	-webkit-flex-flow: column;
	-ms-flex-direction: column;
	flex-flow: column;</b>
}

Now to reorder the boxes we just need to add a declaration for the order of each box.

.l-flex-1 {
	-moz-box-ordinal-group: 1;
	-webkit-box-ordinal-group: 1;
	-webkit-order: 1;
	-ms-flex-order: 1;
	order: 1;
}

.l-flex-2 {
	-moz-box-ordinal-group: 2;
	-webkit-box-ordinal-group: 2;
	-webkit-order: 2;
	-ms-flex-order: 2;
	order: 2;
}

.l-flex-3 {
	-moz-box-ordinal-group: 3;
	-webkit-box-ordinal-group: 2;
	-webkit-order: 3;
	-ms-flex-order: 3;
	order: 3;
}

When you strip out the vendor prefixes it's a lovely bit of syntax:

.l-flex {
	display: flex;
	flex-flow: column;
}

.l-flex-1 {
	order: 1;
}

.l-flex-2 {
	order: 2;
}

.l-flex-3 {
	order: 3;
}

Demo two has the flexbox included and uses media queries so it only happens above 50em. Now the list of sub pages is displayed at the top of the document.

One thing to note at this point is that Firefox doesn't support percentage widths on the ordered boxes. Demo three has 50% width declared on all the boxes and it has no effect in Firefox (screenshot). Your options are either add an extra element inside the box and give it a percentage width, or remove the -moz- prefixes and use the less enhanced layout. This is a 3 year old bug which could means it's not high priority or could mean it's close to the top of the fix me pile. I have no idea how these things work.

Demo four has the main content floated to the left and the first aside floated to the right, a pattern I use in this project.

This is fine in all browsers except Chrome, which goes completely buck mad with disappearing content, overlapping content and huge spaces (screenshot). Somehow the floats in one box throw grenades all over the rest of the page.

Fortunately there are two ways to prevent this.

The easiest method is to clear the floats using overflow:auto or overflow:hidden as in demo five. The clearfix method currently in HTML5 Boilerplate doesn't help.

The second way is to replace the floats with inline-block elements, as shown in demo six.

Opera, IE10 and Safari display things as intended with no surprises, Opera being the only one that works without prefixes. That makes flexbox one area of web standards that will take a step back if WebKit don't squash the bugs and un-prefix before Opera switches rendering engine.

For me, a side effect of this brief foray into flexbox is an extra bit of weight for the argument against vendor prefixes. I'm thankful flexbox is prefixed in Gecko and WebKit as it is buggy. That pretty much explains the purpose of vendor prefixes–they're experimental and need to be thoroughly tested before the prefix comes off.

I am ambivalent though. I use vendor prefixes occasionally and there are plenty that apparently don't have any bugs but remain prefixed.

When I was working on the project that spurred me to write this I initially chose to only use flexbox in Opera and IE10. Firefox and Chrome were broken, time was short, the prototype needed to be sent to the client, and I didn't figure out the fix for Chrome until writing this post and creating the stripped back demos. After giving it some thought I settled for changing display:flex to display:table;caption-side:top and changing order:3 to display:table-caption which works all the way back to IE8. If you don't know what I'm talking about Jeremy Keith explains it better than I ever could in his Re-tabulate post.

This is only a few things I have encountered in a narrow use case of a small aspect of flexbox. My favourite comprehensive article on the subject is Chris Mill's opus Flexbox — fast track to layout nirvana? in which he smashes Betteridge's Law into tiny pieces and I recommend you read it. When flexbox is widely supported and bug free it will revolutionize web layout.

All the demos are on Github.

Resources