Understanding the Albatross
This morning, I read Heydon Pickering’s post on switching from a multiple column flexbox layout to a single column layout without an intermediate step. I spent a bunch of time figuring out why it works.
Go ahead and read it first, if you haven’t already. Everything I’m going to talk about builds on what he has.
You’re back? You haven’t left? You grabbed coffee because why not? Whichever, let’s continue…
The first thing to mention is that the CSS custom properties that Heydon mentions aren’t required. It’s handy but not necessary. The actual calculations that we care about happen on the flexbox child elements.
Essentially, the flex-basis
on the child elements computes to: calc(40rem * 999 - 100% * 999);
The first thing I wondered was why the big numbers. The trick is to essentially have the flex-basis
be big when the container is small and vice versa.
Let’s say we want the child elements to go into a single column at 500px, we would use the following CSS:
flex-basis: calc(500px * 999 - 100% * 999);
Let’s get rid of those 999s, and see what’s going on.
flex-basis: calc(500px - 100%);
When the container is 500px wide, the flex-basis is 0. When the container is 499px wide, the flex-basis is 1px. When the container is 501px wide, the flex-basis is –1px. At 499px, though, we need the flex-basis much higher. It needs to be at least 250px. Two columns at 250px can’t fit side by side. Thus, we need to multiply by at least 250.
flex-basis: calc(500px * 250 - 100% * 250);
When the container is 500px wide, the flex-basis is, again, 0. But when the container is 499px wide, the flex-basis is 250px. When the container is 501px wide, the flex-basis is –250px. Perfect!
Using 999 works just as well. It’s a big number that works for 99.9% of situations. (Although, if you wanted a “breakpoint” at 2000px, the numbers would be off. It would actually break at 1999px instead of 2000px for a two column design. Somebody might get fired for such a bug!)
Equal Columns
If you want equal column widths, you don’t need to set a min
or max-width
. Since all columns have the same, large flex-basis
, the columns will all grow to be the same size.
If you want columns of different widths, it gets a bit trickier. You can use min-width
but you’ll need to set all columns and they’ll all need to add up to 100%. For example, if you want the first of four columns to be 10%, you’ll need to set the other 3 columns to 30% each so that all four add up to 100%. Otherwise, flex-grow
steps in and distributes the space evenly.
If you set a width
or max-width
on a column, that column will be that width when stacked as well as side by side.
No Media Queries
As Heydon says, this technique can work well because no media queries are required—it’s all based on the container size, not the viewport size.