Fluid layouts done right, with Flexbox

In a world of darkness, where no CSS standard ruled the world – one man had one destiny: To kill all nasty CSS hacks. Having defeated tables in an epic battle with divs, our hero witnessed a new enemy rise from the ashes. Known as floats, this ruthless enemy left a flaming trail of devastation whenever the people called upon him. But our hero had a secret weapon: the weapon of flex.

How it used to be

Did any of you develop in the era of using tables for position and structuring your design? It worked, and we got pretty good at it. But it bloated our markup, was overly complicated, and very wrong in regards of semantics and accessibility. It basically got the job done, but nothing more than that. It did everything else wrong.

With the magic of float:left and float:right we could do the same as we did with tables. We were saved! Or so we thought. After transitioning from tables to floats we still missed a lot of the benefits the table elements gave us. Things like equal height columns, and vertical alignment, proved to be something other than a walk in the park when it came to floating.

Floating divs and other elements is more correct semantically, because the style and layout is moved to your stylesheet. It’s more accessible. But for the developer it got a bit too tricky sometimes, as mentioned. A plethora of CSS-hacks, tricks, and quirks, popped up. To do simple things like fixed footer and equal column height you had to think outside the box; switching out display: inline to display: table-cell, wrapping things in extra elements, adjust positioning, faking things, and so on.

What is the flexible box model

The flexible box model is like the other box models. It has content, padding, margin, border, and outline. It works on the semantic you usually use, like the good old div, or the new guys in town: article, aside, header, etc.

When you in your CSS say that an element is of the flexible box model type, that element starts to get almost super powers. As the name implies this models main advantage is its flexible nature. Everything inside a flexbox will be treated as flex children. These kids can easily and dynamically take the same height as the other kids, add liquid space between them, occupy all the space that is available after another element took X pixels, vertical align any block, reorder the visual presentation apart from the semantic one, etc.

By setting display: flex; on your wrapping element, you now have a completely different way of working with positioning and layout. You don’t even need to set margins on these kids because the flexible box model supports dynamic justify, like space-between that just adds space between the elements from the available unused space.

How is flexbox better?

Working with the web has always been perhaps a more growing and evolving business than others. As we advanced in the field of design and UX, we found existing techniques and used/combined them to produce what we needed. As was the case with Tables, a markup not meant for design. Then came floats, which was more meant for design. But as our designs kept evolving even floats started to fail us.

Flexbox is more or less architected from the ground up to actually be the supreme solver of all things positioning and flexibility. With a “tool” that’s from the ground up made to solve all these things, we get a code that is much easier to maintain, more readable, less dependent, and more future proof. During the transition period we will of course have a lot of people that haven’t learned flexbox yet, but in the past we’ve seen the community taking a big part in educating the masses.

We can’t but applaud the fact that we can potentially drop a few JS-plugins and polyfills as flexbox gets better support. And our semantics and the logic of our stylesheet improve. Equal height on divs (columns) - no problem. Reorder DOM-elements when displaying them - no problem. Vertical alignment - no problem. Sticky footer - no problem. Not all of them need extra JS, but we need to produce extra CSS to get it working, and adding more to our code at a later stage might turn really ugly.

However, no matter how sweet this new technology is, we do have to wrestle the ever present browser compatibility issues. But on the bright side, conformance to W3C-standard is pretty high for flexbox in most modern browsers, and non-supporting browsers see a steady decrease on its user base.

Check out html5rocks.com for more information on flexbox performance.

Browser compatibility

Something that’s a bit unique with the flexbox-standard is that it has been implemented twice. We had an intermediate implementation in most modern browsers, during flexbox working draft stage at W3C. And two years later the working draft became candidate recommendation, with major changes to the standard. So, the browsers implemented it all over again, leaving the developers with two different supports for flexbox - yeey!

Other than that, Chrome, Firefox, and Opera have had good support for some time now (from 2012). With IE catching up with the support in their 11th version. IE10 supports its own hybrid between the new standard and the old one. And older browsers (Firefox, Opera and Webkit-based ones) support either the old standard (post 2009), or none (pre 2009). Of course some with vendor prefixes sprinkled over the code based on browser modell.

Check out Can I Use for more on browser compatibility as it’s kind of a big mess. For modern browsers you should get a long way using flexbox standard syntax with the -webkit- vendor prefix added in. flex-wrap and flex-flow (flow is just a short-hand for many other flex-commands that do work) will give you the most problems, since they’re not supported in modern Firefox (as of January 2014). And if IE8 and IE9 are important to you, you’re kind of out of luck. But a polyfill called Flexie JS can be used to make the old 2009-syntax work on older browsers. For the modern standard, the world has yet to invent a polyfill.

If you are eager to start using flexbox now, you can try FlexboxDetective developed here at Enonic. It lets you target browsers with flexbox support by adding classes to the html-element. This way you can provide fallbacks for older browsers. Much like how Modernizer works, just slimmed down as much as possible to just check different kind of Flexbox support.


Fixed and fluid width columns

flex-grow, flex-shrink and flex-auto determine how to fill the remaining space along the main axis.

Fixed width columns - 1
Fixed width columns - 2

Although all items have width set to 100px, only the three first items will be flexible. The last item has both flex-grow and flex-shrink set to 0.

Equal height

By setting item-align to stretch, we tell the flex items to all take the height of the tallest item in the same row. Note that height, min-height and max-height are still respected. Item two is still shorter than the other items since height is set to 120px. 

Equal height example

Advanced example

In Flexboxshopping (jsbin) we have used flexbox to do several things:

  • The header, nav, main and footer element are all flex items with flex-direction set to column.
  • The menu is flexbox.
  • Flexbox is used to give the right column the same height as the element wrapping all the products. The right column also has a fixed width while the product wrapper fills the rest of the width.
  • All the products are flex items with min-width and max-width.
  • The elements inside the product box are flex items. This lets us align the “More information” link to the bottom.

Tip: Try resizing the example to experience flexbox in action.

Note: This example will not work properly in browsers that don’t support the flex-wrap property (Firefox 27 and below). For browsers who don’t support flexbox it will obviously not work at all.

Flexbox CSS properties

The flexible box model uses various properties to control the layout with a containing element and its child elements. Some of the CSS properties are applied to the flex container and others to the flex items.

Flex container properties

display: flex | inline-flex;

A flex container is defined with the display property.  Using the value inline-flex causes the container itself to be rendered inline, and using flex will render the container as a block element. CSS columns do not have any effect on a flex container.

flex-direction: row | row-reverse | column | column-reverse;

The default value is row which will align the flex items horizontally, ordered left to right while column will arrange them vertically, top to bottom. Using either of the reverse values will simply change the order in case you ever need right-to-left or bottom-to-top. When the main axis of the container is horizontal, the cross axis is vertical. The flex-direction determines how many of the other flex properties behave, so the following examples will assume the default horizontal axis unless stated otherwise.

flex-wrap: nowrap | wrap | wrap-reverse;

The default here is nowrap which will place the flex items in a single line. If set to wrap then flex items will wrap to the next line along the cross axis. This does not yet work in Firefox so don’t plan on using multi-line any time soon.

flex-flow: [flex-direction] || [flex-wrap];

This is the shorthand way of setting flex-direction and flex-wrap in the same line of CSS.

justify-content: flex-start | flex-end | center | space-between | space-around

This defines how flex items will be aligned along the main axis. The default is flex-start, so when the main axis is horizontal, the flex items will start on the left. Using flex-end will align the items to the right and center will center them. Using space-between will put an equal amount of space between the flex items and space-around will put space between each item. Of course this is only useful when the combined width of the flex items is less than the width of the container.

align-items: flex-start | flex-end | center | baseline | stretch

This is very similar to the justify-content property but for the cross axis. When the main axis is horizontal, the flex-start and flex-end values will align flex items with the top or bottom of the container respectively. Using center will align them in the middle and baseline aligns them according to the text baseline. The default is stretch, which will make all the flex items the same height as the container unless they have a height or max-height specified.

align-content: flex-start | flex-end | center | space-between | space-around | stretch

This is pretty much the same as justify-content except that it works on the cross axis and only when there is more than one line of flex items.

Flex item properties

The properties float, clear and vertical-align have no effect on flex items.

order: [integer]

If you want to change the default document order of your flex items, simply specify the position by number.

flex-grow: [number]

The number value specifies the proportion that this flex item should grow to take up available space in the container. The default is 0 so this won’t take up extra space. If each flex item has this set to 1 then they will all be the same height as the tallest. If one is set to 3 and the others are set to 1 then that flex item will be three times taller. Of course flex-grow will affect the width rather than height when the main axis is vertical.

flex-shrink: [number]

This is the opposite of grow. The default is 1.

flex-basis: [length] | auto

The default size of a flex item can be specified before the remaining space is distributed. The default is auto.

flex: none | [flex-grow, flex-shrink, flex-basis];

This is shorthand for flex-grow, flex-shrink, and flex-basis. Only the first parameter is required and the default is 0 1 auto.

align-self: auto | flex-start | flex-end | center | baseline | stretch;

This is for aligning individual flex items and overrides the align-items property.