Re: [csswg-drafts] [css-mixins-1] A var()-based model for mixin parameters (#12927)

(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