Mind the Flex-gap
Some thoughts on bridging the CSS generation gap between the world of Flexbox we have now, with margins on child elements, and Flex layout with gaps defined on the parent container. Along the way there’s poetically responsive media-query-free layout — let down by poor plagiarism of a poetry classic.
Look Ma, no media queries
Heydon Pickering is a clever chap. If you’re involved in web dev you should follow him. Last month, his latest gift to the CSS world was a kind of Holy Grail, a Flexbox-based component for laying out a group of items responsively without any media queries. He named it his Holy Albatross, a nod to the angst involved until he was able to see the light (I’d still be in the dark on many things if it weren’t for him).
To keep the net effect “looking flush”, Heydon deploys the Fukol approach of margins on the child items, offset by negative margins on the parent container, but acknowledges that:
“This will become redundant when the
gap
property is more widely supported [in Flex layout mode].”
As Coleridge’s Ancient Mariner might have riffed🤘, when it comes to Flexbox we’ve been promised a lot but not yet quite enough:
“Layout, layout, every where,
Which can grow and shrink;
Layout flexing every where,
But gaps we’ll have to rethink”
The gap generation gap
Right now, if everyone used the latest Firefox, there’d be no rethinking of margins as gaps needed, because since version 63 was released in late October 2018 we can have our layout cake and eat it:
.container {
display: flex;
flex-wrap: wrap;
--modifier: calc(40rem — 100%); /* Ooh! */
column-gap: 2rem;
row-gap: 2rem;
}.container > * {
flex-grow: 1;
flex-basis: calc(var(--modifier) * 999);
}
Unfortunately, right now it’s just Firefox soaring overhead, and there’s no date yet for when the Chromium or Webkit teams will achieve lift-off. Which is a shame, because not only are there roughly 40 to 50 fewer bytes of CSS to write, there’s also less markup if one wants to robustly style the container itself with padding:
But there’s another challenge. How can we distinguish…
- browsers that cover the expanded spec
- from browsers that uphold Flex and Grid layout as originally defined, but not
{row,column}-gap
in Flex layout mode?
We can’t test for:
@supports (column-gap: 1rem) {
/* styles */
}
…because browsers of types 1 and 2 will both pass.
Rachel Andrew has raised this issue in the broader context of testing support of properties and values with partial implementations.
When it comes to gaps, even though the move is away from layout module specific properties towards un-prefixed ones (for example, grid-column-gap
is now well supported as just column-gap
), there is still the shorthand:
grid-gap: {row-gap} {column-gap};
So perhaps, as Simon Lawrence has proposed, we could introduce flex-gap
to squeeze us through the bars of @supports
jail. Then we could have an even more context sensitive albatross:
.container {
display: flex;
flex-wrap: wrap; /* Stop gap */
--margin: 1rem;
margin: calc(var(--margin) * -1);
}.container > * {
flex-grow: 1;
flex-basis: calc(var(--modifier) * 999);
/* Stop gap */
margin: var(--margin);
}/* Generation gap */
@supports (flex-gap: 1rem) {
.container {
flex-gap: 2rem;
} .container,
.container > * {
margin: auto;
}
}
In other words, until some future nirvana when close to 100% of user agents can reliably be assumed to support gaps applied to Flex parent elements, we could prefix those gaps — and get the layout wingspan we want.
Note that we won’t have to prefix gaps when they are applied to Grid or multi-column elements because the concept of explicit gaps has been intrinsic to those layout modules from the start.
It would be great if there could also be a fully algorithmic solution to asymmetric columns using Grid without resorting to a media query, but I haven’t found one yet.