CSS Columns: an underrated layout tool?

Once we are allowed outside of our homes again and can socialize like proper humans, a couple of friends and I have a plan to start up a small 19:th century reenactment club. We'll be mainly focused on taking relaxed walks while looking absolutely dandy.

Anyway, having nothing better to do the other day I wondered what a website for such a club would look like. More specifically, I wondered what a website from the late 1800s would have looked like. Foregoing any deeper design analysis (which could probably have taken up the better part of a master thesis), I simply decided to take something from the period and just recreate it on the web. My choice fell on a newspaper.

An old newspaper with a dense, six-column-layout. Photograph.

I've always liked this dense layout when it comes to news. Sure, each headline is styled a bit differently in an attempt to grab the readers attention, but the differences are minor. Furthermore, with such a limited space for text each article is forced to be very concise and to the point. There simply is no room for click-bait-y nonsense, nor for reporters with delusions of being novelists. Despite its density there is a calm to it.

Choosing the layout tool

So what layout tool would be the best to achieve this design, while of course maintaining responsiveness and accessibility?


My first thought was that this was a job for CSS grid. With each article dong some spanning in an auto-sized grid surely I could come up with a cool layout. But I could not. Grid was just too... griddy. There was a lot of wasted space underneath some articles since their row-mates were longer (just look at the bordered box). If the content was completely static it would probably have been possible, but there would have been a lot of individual tweaking, and the point of the layout would have been lost.

A grid layout that is very rigid. Screenshot.


So maybe I should take a step back and use good ol' reliable flexbox? Well, while it is true that flexbox can put its children in a column as well as then wrap them into multiple columns, this requires the flex container to have a set height. But since I want the content to be dynamic and the page to grow vertically the more space is needed, calculating a height would be quite complicated and probably buggy. As you can see in the screenshot below, the content grows horizontally instead.

A flex layout that overflows to the right. Screenshot.


Turns out taking a step back is what I had to do, but not in that direction. The CSS columns property is about as old as flexbox, but it never got the praise of its cooler sibling, since flexbox was such a revolution in web layout. Nevertheless, this is the perfect place to use it. It does come with a couple of slightly unintuitive quirks though.

At first the syntax seems really straight forward:

column-count: 3;
column-width: 32ch;

So you'd think you'd get three columns at a fixed width, right? But no, what these two properties do is actually more like suggestions, or ideals for the browser to strive towards. column-count can either be set to auto, in which case there will be as many columns as can fit, or it can be an integer. When it is an integer it works more like how an imaginary property called max-column-count would work. It caps at the given value, but when space is limited the number of columns is reduced. Automatic responsiveness!

When does it know at what points to switch to fewer columns though? Well that's where the second property comes into play.

column-width can also be set to auto, in which case the width of each column is determined by the column count. If set to a specific width however, then it works more like an imagined column-min-width. Whenever a column becomes squeezed enough to go below the set width the number of columns will instead be reduced, and the width of the new columns will be larger again. In other words, using column-width we can give the layout breakpoints at which the number of columns will change. More automatic responsiveness!

Finally there are a couple of properties that are just the absolute icing on the cake, and I send all my love to the people who defined and implemented them. ❤️

column-gap: 2rem;
column-rule: 1px solid black;

column-gap does exactly what you think: it makes space between the columns. Only between them, not around, and there is no need to do any CSS trickery to put margin on every element but the last, like we sometimes do with flexbox.

column-rule puts borders between the columns. Any size, any kind, any color. And they end up right in the middle of the gap. I love it.

The result

So here is the final code:

column-count: 3;
column-width: 32ch;
column-gap: 2rem;
column-rule: 1px solid black;

And the resulting layout:

A column layout that just works great. Screenshot.

This gets us a multi-column layout where the content starts in the left column and then flows to the right, yet with an implied maximum width (3 columns at 32ch each) which makes the page expand down when there is a lot to show, while the columns are always equally high. The text breaks in the middle and continues in the next column.

Here is a demo page where you can look at the final HTML and CSS. Maybe you can find a use for the column layout in your project? Let me know on twitter!

A final note

I didn't explore the possibilities of CSS grid mason layout for this article, since at the time of writing it is still just a proposal and not supported by any browsers (except Firefox, behind a flag). However, it might actually be the superior choice in the future, since it would allow the articles that are first in the list to appear at the top of the page, instead of in the leftmost column.

I will revisit this topic when the time comes.