Flexbox Taking Advantage Of Flexible Boxes

03 Jun 2013

The Flexible Boxes (or Flexbox) specification in CSS3 is one of the newest solutions for making the development of responsive layouts easier and much more sane. The goal of the specification is to accomodate websites on a variety of screen sizes and resolutions, and be able to maintain structural integrity through switching between portrait and landscape modes, or other changes that may be out of the developer's control.

Let's write our markup as if we had received the following mockups for a set of modules.

Desktop

Mobile

In previous projects, we would most likely create a <div> for the container, inside of which we would include three floated <div>s, each containing a module. Down to its basic fundamentals, it may be set up something like this.

// HTML //
<div class = "container">
  <div class = "module">
    <h1>Headline</h1>
    <p>Lorem ipsum...</p>
  </div>

  // Repeat two more modules

</div>

// CSS //
.container {
  float:left;
  width:100%;
}

.module {
  float:left;
  width:33.33%;
}

This doesn't look bad now, but adding more columns with a variety of content types and lengths creates the need to do a lot of on-the-fly math. With the advent of Flexbox, there is now (finally) a simple alternative to this.

Let's first set up the sample markup based on the mockups, which will look the same as the markup we used while using floats.

<div class = "banner">
  <div class = "h">Header</div>
</div>
<div class = "flex_container">
  <div class = "flex_child">
    <h1>Headline</h1>
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam fermentum aliquet massa at fermentum. Maecenas sagittis porttitor lacus sed commodo. Suspendisse consectetur diam vel metus blandit tempus. Duis nec neque dolor. Duis in nunc metus. Aliquam erat volutpat.</p>
  </div>
  <div class = "flex_child">
    <h1>Headline</h1>
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam fermentum aliquet massa at fermentum. Maecenas sagittis porttitor lacus sed commodo. Suspendisse consectetur diam vel metus blandit tempus. Duis nec neque dolor. Duis in nunc metus. Aliquam erat volutpat.</p>
  </div>
  <div class = "flex_child">
    <h1>Headline</h1>
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam fermentum aliquet massa at fermentum. Maecenas sagittis porttitor lacus sed commodo. Suspendisse consectetur diam vel metus blandit tempus. Duis nec neque dolor. Duis in nunc metus. Aliquam erat volutpat.</p>
  </div>
</div>

Easy, just like we have always done. We'll set up much of the CSS the same way too.

// Colors //
$orange:#E74C3C;
$white:#FFE7A1;

* {
  box-sizing:border-box;
  font-family: 'Roboto', sans-serif;
}

h1 {
   color:$orange;
}

p {
  color:#3e3e3e;
}

I'm using Sass for this example. If you're using vanilla CSS, everything can be written the same way aside from the color variables.

First, make sure that the flex-container is the flex display property, along with its corresponding webkit prefix.

.flex-container {
  display: -webkit-flex;
  display: flex;
}

Once the the display property is set, we still need to declare the flexible behavior of the container and it's children. To do this, we will use the flex-direction property. Flex-direction uses rows and columns, which force the child elements to follow each other horizontally or vertically, respectively.

For the wider screens, we want to the children to be laid out horizontally, so we'll make sure to declare them as rows by setting the property of the container. This is important to note, that the flexbox properties are set on the parent element of the elements that need to be positioned.

.flex-container {
  -webkit-flex-direction: row;
  flex-direction: row;
}

We want the container (and therefore the sum of the children) to take up the entire width of the screen, so we'll add the width:100% to the container, giving us the following complete container.

.flex-container {
  width:100%;

  display: -webkit-flex;
  display: flex;

  -webkit-flex-direction: row;
  flex-direction: row;
}

Since the flexbox properties are called on the parent elements, we have to do very little (mostly aesthetic) styles on the children. We don't even have to provide a width since the 100% width and flex property on the container forces the sum of the children to take up 100% of the page.

.flex_child {
  padding:1em;
  background-color:$white;
}

Running this now will give you a great idea of how flexbox works. Notice how the boxes automatically resize without having to specify widths. So simple!

Unfortunately, we still run into the same problems when it gets too skinny, and we want the small screen experience to match what we had on the mockups.

This is extremely simple, and requires only a simple media query and property change.

@media all and (max-width:700px) {
  .flex_container {
    -webkit-flex-direction: column;
    flex-direction: column;
  }
}

Like I mentioned earlier, changing the flex-direction on the container will make sure the children follow each other vertically instead of horizontally.

Here is a CodePen of the whole thing together.

Check out this Pen!

Now, after seeing some of the wonderful things that these flexible boxes can do with such a minimal amount of effort, I'm going to break your heart. Being so new, the browser compatibility for flexbox leaves a lot to be desired. There is no support at all for any Internet Explorer before IE10, and even that only supports an old draft of the spec as does Safari.

There is a polyfill to make Flexbox work in legacy IE browsers, though it is a few years old and due to the new version of the spec being released, it may or may not work the same way. I would definitely put in some research before using any of this in production.

Flexbox is an exciting step towards creating specs that allow us to create fluid, responsive layouts without having to resort to hacks (regardless of how accepted they are). As browser and developer support increases, flexbox should only continue to gain traction as a solid alternative to floats for responsive layouts.