An Interesting Limitation of CSS Custom Properties
At 4/19/2024
As soon as I read my teammate Paul’s explanation of The Math Behind Nesting Rounded Corners, I wanted to recreate it using custom properties and calc
.
I thought I’d be able to do something like this:
:root {
--radius: 1em;
--padding: 0.375em;
}
.container {
border-radius: max(var(--radius), 0em);
padding: var(--padding);
}
.container .container {
--radius: calc(var(--radius) - var(--padding));
}
Code language: CSS (css)
But that doesn’t work. It creates what the Custom Properties specification calls a “dependency cycle,” where the value of --radius
is dependent on itself.
I tried working around this using CSS counters, but as of this writing those don’t work with calc
. I also tried setting --radius
using @property
with inherits: true
, but the result was the same as before.
So best solution I’ve come up with is to manually iterate a separate property:
:root {
--radius: 1em;
--padding: 0.375em;
}
.container {
border-radius: max(calc(var(--radius) - var(--padding) * var(--depth, 0)), 0em);
padding: var(--padding);
}
.container .container {
--depth: 1;
}
.container .container .container {
--depth: 2;
}
.container .container .container .container {
--depth: 3;
}
Code language: CSS (css)
Here are those styles in action:
It’s kind of a bummer having to guess how many levels of nesting you’ll need, but it should be manageable for smaller values like border radii.
There’s already some talk of new CSS features that would simplify this sort of thing. I’m sure we’ll have a more elegant solution sooner or later.