Skip to main content

An Interesting Limitation of CSS Custom Properties

By Tyler Sticka

Published on November 17th, 2022

Topics

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.

Comments

Jakub Jankiewicz said:

This is a typical misunderstanding form people that use JavaScript (or any other programming language). Custom Properties (CSS variables) don’t create something like JS scope. Every variable has only one instance. CSS inheritance is nothing like JavaScript scope.

Jane Ori said:

I wrote less and sass inherit(–var) functions to make this possible:
https://codepen.io/propjockey/pen/rNdOWGB