Unholy Albatross

| permalink | css

Updated July 16, 2020: new and improved using clamp()

Container query has been one of the most requested features of CSS for a while now, and though we still don't have the real thing, we can finally collapse columns at arbirary breakpoints thanks to Holy Albatross by Heydon Pickering.

It is a very clever way to responsively stack 3+ columns into rows based on container size in a single step, using the following property:

flex-basis:calc((breakpoint - 100%) * 999); flex-grow:1

This formula allows the column to switch between negative and positive flex-basis (at a minimum 999px wide due to 1px * 999), which combined with default flex-shrink value of 1 allows the column to expand to full width as soon as 100% container width falls below the breakpoint.

However, because it takes over flex-basis and flex-grow, this technique makes it hard to set the width of columns.

Note: Negative flex-basis is supposed to be invalid, thus defaulting to auto. However it looks like it's behaving as 0 instead. This helps us because column content size doesn't interfere with flex-grow, but it's probably a bug.

Unholy Albatross, harnessing the black magic of clamp()

To solve this, I moved his formula into min-width, combined with clamp():

min-width: clamp(0px, (var(--breakpoint) - 100%) * 999, 100%);

See CodePen

By moving container query to min-width, it frees up flex-basis and flex-grow so the width can be set freely.

Reversing order of stacked columns

A common use case is to raise the right hand column to the top when stacking columns vertically, but changing the order doesn't seem to be possible here.

The only value that acts as the trigger is the width value such as (40rem - 100%) * 999, we can't alter the order property with it because order only wants integer, and our trigger value must contain a width.

However, flex-direction:row-reverse has a curious property - the x direction is reversed, but the row still wraps downwards, this means when columns are 100% wide it behaves like flex-direction:column.

Now my first instinct is that I need to reverse the source ordering of the columns and apply flex-direction:row-reverse to it so it shows up normally, and when the column stacks the order is automatically reversed.

But touching source ordering feels dirty.

So as an alternative, I reversed the order via CSS, and then flip it back:

.v-reverse {flex-direction:row-reverse}
.v-reverse > *:nth-child(1) {order:-1}
.v-reverse > *:nth-child(2) {order:-2}
.v-reverse > *:nth-child(3) {order:-3}
.v-reverse > *:nth-child(4) {order:-4}
/* extend as needed */

Obviously it's not ideal having to define the order for every child, but this is the best we can do for now until real container query is supported by browsers.

A shameless plug here - I've incorporated this into my DryKit framework, check it out.