- From: andruud via GitHub <noreply@w3.org>
- Date: Wed, 28 Jan 2026 14:33:26 +0000
- To: public-css-archive@w3.org
(This post to be understood in the context of the old `env()`-based spec.)
> Would be helpful to have some illustrations of the impact of this change.
The primary changes in this proposal (from an author's perspective) are quite simple:
- Authors use `var()` to reach mixin parameters/locals, rather than `env()`. Mixin parameters _shadow_ custom properties on the element (same as `var()` within custom functions).
- Authors use the familiar `--name:value` syntax to specify locals, rather than `@env`.
Beyond that, I would not describe this as a "change"; this is an attempt at answering questions the old spec (now removed) _didn't actually answer sufficiently_. Most importantly: when/how `env()` resolves. I already wrote about that in the original post (I won't reiterate that), but I'll provide a more specific scenario:
Say you have a mixin with a typed parameter, e.g. a `<length>`:
```
@mixin --m(--x <length>) {
@apply --inner(env(--x));
}
```
and then you do `@apply --m(var(--thing))`. How is `--x` to be understood on the inside of `--m` here? It's specified to be a `<length>`, but we have no way of actually making into a real `<length>` without the context of an element; does that mean `env()` can now substitute into values that (still) contain other substitution functions (literally `var(--thing)`)? Does that in turn mean that, if `--inner`'s first parameter requires a `<color>`, it's valid to do `@apply --inner(env(--x))` since it's effectively `@apply --inner(var(--thing))`? At what point do we then enforce the `<length>` constraint? For the purposes of a mixin's internal logic, this seems to _nullify_ the type system, and, generally, a mixin won't necessarily be able to "act" (e.g. branch conditionally) on the values being passed in.
This requires some explanation, and we get a lot of explaining for free by leaning on the already well-defined semantics for custom functions. If we treat every mixed-in declaration as having been placed inside a function call chain equivalent to the mixin apply chain (see previous examples), then we have a detailed description for how/when `var()` (formerly `env()`) should resolve, how/when types are understood (etc). This primarily unblocks implementations of mixins in browsers by explaining how it works in sufficient detail; I'm not aware of any drawbacks or noteworthy differences authoring-wise beyond what's stated near the start of this post.
It _does_ however open the door to [hygienic renaming](https://drafts.csswg.org/css-mixins-1/#var-hygiene) of variables (#13113), and gives a path towards element-dependent block conditionals (#12909) within mixins as well.
--
GitHub Notification of comment by andruud
Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/12927#issuecomment-3811657215 using your GitHub account
--
Sent via github-notify-ml as configured in https://github.com/w3c/github-notify-ml-config
Received on Wednesday, 28 January 2026 14:33:27 UTC