CSS columns made easier with flexible boxes

The problem

One of the most annoying things in CSS has always been the lack of out-of-the-box support for displaying content in columns. The usual workaround for this has been to use the float attribute and give each column a certain width, for example 33% each if we want three columns, or somewhat less if we want to leave margins in between (also if we want to leave paddings instead of margin, unless the columns have the border-sizing property set to border-box). But as you can see there is quickly some amount of unnecessary complication and hard-coding coming up, bloating our styling code and bringing potential problems. Not to mention having to clear the floats after the last floating element, which is also a common cause of headaches.

There are many frameworks out there like Bootstrap, which are helpful if you want to adjust your columns to a well-defined grid if you know how many columns you want and how wide they should be. But, what if we don’t know this in advance, or you just want to be more flexible?

Captura de pantalla 2014-10-15 a les 12.06.08Captura de pantalla 2014-10-15 a les 12.03.59Captura de pantalla 2014-10-15 a les 12.06.27Captura de pantalla 2014-10-15 a les 12.05.18

We will show you how to program a slider (see above) that will allow you to generate an arbitrary number of slices and even change the spacing between them (in real time). Here things start to get complicated and we need not only CSS but JavaScript calculations –or do we?

The good news

Now the CSS 3 spec includes something called flexible box, or just flexbox. Essentially, it lets us easily make the child elements automatically stretch to fit their container, with only two CSS rules, one for the container and one for the children:

.container {
  display: flex;
}
.child {
  flex-grow: 1;
}

The flex-grow attribute is used to set the size of each element relative to its siblings. Setting it to 1 for all will make them all of equal size, and setting it, e.g, to 2 for a certain element will make it two times bigger than the rest.

We don’t have to hard-code any column width anymore and, even better, we can define any margin and padding in between the elements. We can even change them on the fly, and the browser will take care of stretching all those widths automatically, so that they always exactly fill the container.

This can also be used to fit a container space vertically instead of horizontally, by adding

.container {
  flex-direction: column;
}

(Yes, I also find the word “column” misleading!)

The bad news

All modern browsers seem to implement this feature in the latest spec (i.e, with the aforementioned syntax), BUT some of them (Safari on Mac, Chrome on iPad, Safari on iPad) present a little problem –they seem to round the elements’ dimensions and spacings before rendering, causing them to not always fit the container exactly, even if the thing mostly works.

If both pixel-perfectness and cross-browser compatibility are important for you, unfortunately at the time of this writing (October 2014) you might have to dig into older specifications –and this can get tricky, because several different ones have been written in the last years already. In our case, being able to restrict to Webkit-based browsers (Chrome, Safari) this is what worked for us:

.container {
  display: box;
  display: -webkit-box;
}
.child {
  box-flex: 1;
  -webkit-box-flex: 1;
}

Further information

You can see a live example (using the newest specification) here: http://plnkr.co/edit/wWco6QpbNy2PijgNDfbB?p=preview

For more information on the topic you can check this article: http://css-tricks.com/snippets/css/a-guide-to-flexbox/

And here is a more technical description: https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Flexible_boxes

Tags: , , ,

Comments are closed.