Debug panel

Close debug panel
Roma’s Unpolished Posts

Renaming Outer Variables in CSS Functions

Published on:
Categories:
CSS Functions 3, CSS Variables 9, CSS 87
Current music:
österreich I’ll Take You Everywhere
Current drink:
Thyme, rosemary & lemon infusion

In one of the first drafts of the custom CSS functions by Tab Atkins-Bittner, if you wanted to use variables from the outer scope, you had to explicitly list them when defining the function like this:

@function --foo(--arg1, --arg2) using (--var1, --var2) {…}

There was some pushback from many people about this, including from me, and, eventually, this restriction was removed, with all custom properties from the outer scope now being available inside the custom functions without listing them. Great!

At the time, I wondered if we could reintroduce the using keyword or something similar as something that could allow us to rename the variables in the outer scope, allowing us to use them in the function’s scope with different names.

@function --foo() {
	@return var(--bar);
}

@function --baz() using (--bar as --outer-bar) {
	--bar: something;
	/* will be `--a: something` */
	--a: --foo();
	/* We can still access outer `--bar` */
	--b: var(--outer-bar);
}

Later, while playing with the currently specified custom functions in Chrome Canary, I found out that we already can kinda do the same with the optional arguments and defaults. The above example could be written as:

@function --foo() {
	@return var(--bar);
}

@function --baz(--outer-bar: var(--bar)) {
	--bar: something;
	/* will be `--a: something` */
	--a: --foo();
	/* We can still access outer `--bar` */
	--b: var(--outer-bar);
}

And here is a live, although not very practical, example:

2 * x =
2 * (x + 1) =
@function --double() {
	result: calc(2 * var(--x));
}
@function --plus-one-and-double(--outer-x: var(--x)) {
	--x: calc(var(--outer-x) + 1);
	result: --double();
}
<div style="
	--x: 2;
	--preview: --double();
">2 * x = </div>
<div style="
	--x: 2;
	--preview: --plus-one-and-double();
">2 * (x + 1) = </div>

The problem we are solving: if we have some function like --double(), which does not use arguments, and is just accessing the variables from its outer scope, can we use it inside another function with a different --x without overriding it in that outer scope?

The solution: use an argument, and assign its default value using that variable. This way, the function will get that variable’s value and assign it to a different variable:

@function --plus-one-and-double(--outer-x: var(--x)) {…}

Now, inside that function’s body, we’re free to redefine that variable, with the original value staying accessible with the old value in our argument!

This allows us to redefine this variable, call our function in question, all without touching and modifying the outermost scope.

Neat. I don’t know if this will ever be useful, but hey!


This is the second post from the series that I started with Functional Capturing about some of my initial experiments with custom functions. It was in my drafts for a long time, but because the feature is relatively useless, I did not end up finishing it.

Until now — all because with the ongoing work on inherit(), there was an issue opened by Anders Hartvoll Ruud, in which I managed to use this feature in an argument. Fun!

Please share your thoughts about this on Mastodon!