Using Flexbox: Mixing Old and New for the Best Browser Support

Published by Chris Coyier

Flexbox is pretty awesome and is certainly part of the future of layout. The syntax has changed quite a bit over the past few years, hence the "Old" and "New" syntax. But if we weave together the old, new, and in-between syntaxes, we can get decent browser support. Especially for a simple and probably the most common use case: order-controlled grids

The HTML

A semantically meaningless wrapper goes around the three main areas and will set the flexbox context. Each of the areas is semantically marked up and will be turned into columns.

<div class="page-wrap">
  
  <section class="main-content" role="main">
    Main content: first in source order
  </section>
  
  <nav class="main-nav" role="navigation">
    Links
  </nav>
  
  <aside class="main-sidebar" role="complementary">
    Sidebar
  </aside>
    
</div>

The end result looking like this:

Flexbox Context

We need to make the container for our columns a flexbox display context. Just by doing this, all direct children of this element become flex items. Doesn't matter what they were before, they are flex items now.

Right away we need to weave the old, new, and tweener syntaxes together. Order is important here. Since the display property itself isn't prefixed, we need to make sure we don't override newer syntaxes with older syntaxes for browsers that still (and probably always will) support both.

.page-wrap {
  display: -webkit-box;      /* OLD - iOS 6-, Safari 3.1-6 */
  display: -moz-box;         /* OLD - Firefox 19- (buggy but mostly works) */
  display: -ms-flexbox;      /* TWEENER - IE 10 */
  display: -webkit-flex;     /* NEW - Chrome */
  display: flex;             /* NEW, Spec - Opera 12.1, Firefox 20+ */
 }

Controlling Column Widths

Our goal here is a 20% / 60% / 20% grid.

Step 1 is to set our main content to the 60%.
Step 2 is to set the outside sidebars to fill the remaining space equally.

Again we need to weave together old, new, and tweener syntaxes.

.main-content {
  width: 60%;
}
.main-nav,
.main-sidebar {
  -webkit-box-flex: 1;      /* OLD - iOS 6-, Safari 3.1-6 */
  -moz-box-flex: 1;         /* OLD - Firefox 19- */
  width: 20%;               /* For old syntax, otherwise collapses. */
  -webkit-flex: 1;          /* Chrome */
  -ms-flex: 1;              /* IE 10 */
  flex: 1;                  /* NEW, Spec - Opera 12.1, Firefox 20+ */
}

In the new syntax, setting the width for the sidebars isn't necessary as it will fill the remaining 40% equally making them both 20%. But I found not setting it cause some width collapsing with the old syntaxes.

Column Re-Ordering

We want the main content to visually appear in the middle, but be first in the source order. Easy cheesy in flexbox, but of course we need to weave together the new, old, and tweener syntaxes.

.main-content {
  -webkit-box-ordinal-group: 2;   /* OLD - iOS 6-, Safari 3.1-6 */
  -moz-box-ordinal-group: 2;      /* OLD - Firefox 19- */
  -ms-flex-order: 2;              /* TWEENER - IE 10 */
  -webkit-order: 2;               /* NEW - Chrome */
  order: 2;                       /* NEW, Spec - Opera 12.1, Firefox 20+ */
}
.main-nav {
  -webkit-box-ordinal-group: 1;  
  -moz-box-ordinal-group: 1;     
  -ms-flex-order: 1;     
  -webkit-order: 1;  
  order: 1;
}
.main-sidebar {
  -webkit-box-ordinal-group: 3;  
  -moz-box-ordinal-group: 3;     
  -ms-flex-order: 3;     
  -webkit-order: 3;  
  order: 3;
}

Browser Support

If you do all this weaving, you can get:

  • Chrome any
  • Firefox any
  • Safari any
  • Opera 12.1+
  • IE 10+
  • iOS any
  • Android any

The biggest limiting factor of course being IE, but otherwise it's pretty good. If you're doing a mobile-specific version of a site, you're in even better shape. If someone can test it on Windows Phone, lemme know.

Firefox 19- is a bit buggy and you'll need to watch it. For instance, in this demo I wasn't able to figure a way to force the sidebars to actually be 20%. The just collapse to the width of the content inside, which is a bit arbitrary as it's text. I also needed -moz-box-flex: 1; on the main content (60%) otherwise it would stretch to be as wide as the widest paragraph as if it had white-space: nowrap, which is just inexplicable to me.

Demo

On CodePen:

Check out this Pen!

Need more details about Flexbox?

Check out our complete guide.