Remember when Ahmad Shadeed wrote about that border-radius
“toggle” he found in Facebook’s CSS? It was interesting! I covered it. A few weeks after that surge of linkage, a couple of articles came out digging into it a little deeper.
In “Evaluating Clever CSS Solutions,” Michelle Barker wonders how clever is too clever?
While undoubtedly clever, and super interesting to read about, I side with Robin Rendle in the CSS-Tricks newsletter when he says:
I can’t help but feel that it’s a little too smart.I have to agree here. Tricks like this have their place, and Facebook (which can clearly afford to hire the best of the best CSS developers) might be one of them. But speaking personally, when forced to pick between a trick like this and an ever-so-slightly less optimal but far more readable solution (say, a media query), in 99% of cases I’d plump for the latter.
Michelle is aware that a media query isn’t the same solution here. A non-clever solution would be a container query. I agree as well. I almost never opt for tricky solutions in production, as even if they seem to work, I worry about the long term maintenance and sometimes even the fragility of the solution.
Stefan Judis looked at how we might pull of the same “conditional border-radius” idea only using the upcoming container queries syntax.
/* If the container's width is equal to or greater than
the viewport width, remove the border-radius */
@container (width >= 100vw) {
.conditional-border-radius {
border-radius: 0;
}
}
That’s pretty darn clear to me. Stefan also mentions that if we could use the theoretically upcoming @when
feature, it could be even clearer:
@when container(width >= 100vw) {
.conditional-border-radius {
border-radius: 0;
}
}
@else {
.conditional-border-radius {
border-radius: 1em;
}
}
That is a big maybe, as there is no evidence these brand new specs will overlap like this. I hope they do though. CSS has gotten much more logical and readable over the years and this would keep that train moving.
Oh, and I mentioned this in the last article…
The
9999
multiplication means that you’ll never get low-positive numbers. It’s a toggle. You’ll either get8px
or0px
and nothing in between. Try removing that part, resizing the screen, and seeing it sorta morph as the viewport becomes close to the component size
But I regretted not putting a video in there to make the concept clearer, so I’ll rectify that here.
I don’t think it’s ‘too clever’ although all the CSS experts here are in my ‘CSS Guru’ list so I won’t dismiss the suggestion!
What this did do, is make me think of more subtle ways to optimise for small screen sizes and think about the little things that help and hinder a design.
I wasn’t aware of @when and @if, I will read the spec now. I am guessing this will mean we don’t need to test for screen resizing, viewport changing and orientation changes?
I am guessing the @when @if will be the observer behind the scenes like a media query?
100vw != 100%
when the scroll bar appears, so even when the container query starts respecting view units, in this case I don’t think it will work.The same is true of the mentioned Facebook’s trick. When there is scrollbar, the trick just doesn’t work.
Only workaround is to use JS: https://twitter.com/pjchrobak/status/1451571036466688004
I think I recently figured out a CSS only solution for getting the viewport width minus the scroll bars.
Basically, use CALC and a CSS variable.
I found the CALC part on Stack Overflow, and I thought “What if I used that as a CSS variable?”.
It seems to work well in my tests. You can check out a demo here…
I’d love to hear people’s thoughts.
The value of the CSS variable is computed at the time of use, that is, relative to the place of use, not the place where they are declared.
So your solution works in your case because
100%
forpadding
is computed based on parent width, although doesn’t work forborder-radius
, because for it100%
is computed based on element width.Good to know. I had been wondering if there might be a gotcha somewhere. Even so, it should be a useful trick in any situation where you need to line up an absolute or fixed positioned element with a max-width element.
I would like to see something like this, but with relative container query units:
border-radius: clamp(5px, 1vw, 20px);