Re: [csswg-drafts] [css-mixins-1] Auto-wrap mixin body in `@result` if omitted? (#13524)

The CSS Working Group just discussed ``[css-mixins-1] Auto-wrap mixin body in `@result` if omitted?``.

<details><summary>The full IRC log of that discussion</summary>
&lt;fantasai> TabAtkins: Currently mixins, like functions, can have local variables.<br>
&lt;fantasai> TabAtkins: Helps with DRY.<br>
&lt;fantasai> TabAtkins: We need some way to distinguish local variables, which are private to the mixin, vs custom properties in the out put of the mixin.<br>
&lt;lea> q+<br>
&lt;fantasai> s/out put/output/<br>
&lt;astearns> ack ntim<br>
&lt;fantasai> TabAtkins: Current model distinguishes by using the @result {} rule, which is used to wrap all of the output of the mixin.<br>
&lt;fantasai> TabAtkins: Anything outside @result is mixin-internal stuff.<br>
&lt;fantasai> TabAtkins: Chose syntax to match the syntax of @function.<br>
&lt;fantasai> TabAtkins: Question from Lea is, can we avoid writing @result in as many cases as possible.<br>
&lt;fantasai> TabAtkins: My opinion is to not make such a heuristic, and require @result always.<br>
&lt;fantasai> TabAtkins: Otherwise no clear syntactic distinction between locals and custom property outputs.<br>
&lt;fantasai> TabAtkins: And not being able to tell is not great. Should be easy to scan quickly and see what's internal vs external.<br>
&lt;fantasai> TabAtkins: This is harder because mixins can have complex conditional logic and nested rules.<br>
&lt;astearns> ack lea<br>
&lt;fantasai> Lea: I can live with this either way. We can always make things optional later even.<br>
&lt;fantasai> lea: But I think this makes simple mixins very noisy.<br>
&lt;fantasai> lea: Introduces an extra level of nesting<br>
&lt;fantasai> lea: I will point out that all of us, while making mixin examples, forgot the @result. Including Tab himself!<br>
&lt;fantasai> lea: But having @result added later in the rule change behavior of previous declarations is a bit confusing also.<br>
&lt;kizu> `@mixin —foo => {}` lol<br>
&lt;lea> scribe+<br>
&lt;fantasai> lea: I'm not a huge fan of @result overall. Separates computation from usage<br>
&lt;lea> lea: Not a huge fan of `@result` overall, it separates computations from their usage, cannot easily have structure (e.g. set a local on child to a different value unless you jump through hoops)<br>
&lt;kizu> q+<br>
&lt;astearns> ack kizu<br>
&lt;fantasai> kizu: We need some way to have locals.<br>
&lt;fantasai> kizu: I would be ok to have @locals<br>
&lt;fantasai> kizu: So by default everything is public<br>
&lt;miriam> q+<br>
&lt;fantasai> kizu: I agree that it's easy to miss, and hard to understand what's going on, and your custom variables become local variables<br>
&lt;fantasai> kizu: so ...<br>
&lt;lea> q+<br>
&lt;fantasai> kizu: Authors will count mixin as a way to not repeat themselves and re-use their CSS<br>
&lt;fantasai> kizu: For more complex cases, can use @locals<br>
&lt;astearns> ack miriam<br>
&lt;fantasai> miriam: I agree, needing @locals is the special case, not the main case.<br>
&lt;fantasai> miriam: So ideally that's what would get extra syntax -- making something loca.<br>
&lt;astearns> ack lea<br>
&lt;lea> lea: Another advantage of `@locals` is it can be used *outside* of mixins<br>
&lt;fantasai> lea: common in regular CSS to have computations that don't make much sense outside of that rule<br>
&lt;miriam> +1<br>
&lt;kizu> q+<br>
&lt;lea> lea: Can have short form for a single local too<br>
&lt;miriam> (though that's something functions solve as well)<br>
&lt;lea> lea: TBD whether you would need to just declare your locals once with this or whether you would need to use this everywhere you use the local<br>
&lt;fantasai> lea: TBD whether you would need to just declare your locals once with this or whether you would need to use this eveyrwhere you use the local<br>
&lt;kizu> Maybe related: https://github.com/w3c/csswg-drafts/issues/11798 ? So not a `@namespace`, but `@local {}`?<br>
&lt;astearns> ack kizu<br>
&lt;TabAtkins> q+<br>
&lt;fantasai> kizu: Maybe name @local and have some way to expose outside of mixins<br>
&lt;lea> oh and agree with miriam that extra locals are the special case, not the default<br>
&lt;fantasai> kizu: but wrapping in @local would let it be limited to this lexical scope<br>
&lt;fantasai> kizu: and then also use it for this mixin<br>
&lt;fantasai> kizu: The only extra thing, if it is used like this in mixin, means you're not wrapping the rule<br>
&lt;fantasai> kizu: verything inside will be using these local values<br>
&lt;fantasai> kizu: but in mixins, you'll want to define @local with some custom properties inside<br>
&lt;fantasai> kizu: and then have custom properties that use those values outside of @local<br>
&lt;fantasai> kizu: lots to think about if we make this a general feature for lexical scoping<br>
&lt;astearns> ack TabAtkins<br>
&lt;fantasai> TabAtkins: main reason Anders and I are against @locals are that @mixin and @function have very similar structure and usage.<br>
&lt;miriam> q+<br>
&lt;fantasai> TabAtkins: having them differ gratuitously in their syntax, I think will cause more confusion than it helps<br>
&lt;fantasai> TabAtkins: Good to have similar constructs spelled similarly<br>
&lt;fantasai> TabAtkins: @function has local variables and a result property<br>
&lt;fantasai> TabAtkins: @mixin having @result is parllel<br>
&lt;fantasai> TabAtkins: romain has same opinion<br>
&lt;fantasai> TabAtkins: We also discussed with Chris Coyier, he immediately understood what the at-rule was doing<br>
&lt;astearns> ack miriam<br>
&lt;fantasai> TabAtkins: So want to keep it because it means similar things are spelled similarly<br>
&lt;fantasai> miriam: I don't think @result is confusing, just bloated.<br>
&lt;fantasai> miriam: Disagree with premise that @function and @mixin only differn in value space or function<br>
&lt;fantasai> miriam: From author view, whether contents are private or public is another difference<br>
&lt;fantasai> miriam: Custom properties in @function are implementation, in @mixin are part of the output<br>
&lt;lea> q+<br>
&lt;fantasai> miriam: Feels like part of the fundamental difference<br>
&lt;fantasai> TabAtkins: I don't understand<br>
&lt;fantasai> miriam: your goal with writing a mixin is to output properties, so outputing custom properteis is reasonable part of that<br>
&lt;lea> +1 miriam<br>
&lt;fantasai> miriam: but functions, not the goal<br>
&lt;fantasai> miriam: custom properties end up being an internal thing, it's reasonable<br>
&lt;fantasai> miriam: So disagree that mixin custom properties being public is confusing<br>
&lt;kizu> +1 to Miriam — functions are at a value level, and authors won’t expect them to output anything other than the `result:`<br>
&lt;fantasai> TabAtkins: i'm confused why you think top-level --foo: whatever in a ixin should be public<br>
&lt;astearns> I agree with Miriam, too<br>
&lt;fantasai> miriam: A big difference between function and mixin is that mixin has public properties, and a function doesn't.<br>
&lt;fantasai> miriam: therefore I'm not surprised that there's a different spelling. They are different features, aligns with the different purposes of these features.<br>
&lt;fantasai> TabAtkins: So mixin shouldn't have local variables?<br>
&lt;fantasai> miriam: No, just saying that they don't have to be spelled the same.<br>
&lt;fantasai> miriam: If we need to mark them as local when they should be local, that's reasonable.<br>
&lt;fantasai> miriam: I'm disagreeing with you and Anders saying it's confusing to use @local instead of @result<br>
&lt;fantasai> astearns: Agree, I'm not convinced that we need to maintain consistency between functions and mixins here.<br>
&lt;fantasai> miriam: Indeed, I'm arguing against the consistency argument here.<br>
&lt;lea> ergonomics > consistency<br>
&lt;fantasai> TabAtkins: I disagree, consistency is important to language design<br>
&lt;fantasai> lea++<br>
&lt;fantasai> miriam: It's what we did inside functions that doesn't fit the language. Because otherwise this spelling is a custom property. Should behave like other properties. no reason to be suddenly private.<br>
&lt;fantasai> miriam: Functions is where we're giving them special behavior<br>
&lt;lea> it's even a TAG principle (that I introduced when I was in the TAG): https://www.w3.org/TR/design-principles/#consistency<br>
&lt;fantasai> TabAtkins: A local is just a way to spell an argument you can't pass.<br>
&lt;fantasai> TabAtkins: Without locals, using unpassed arugments and defaults is the easy way to spell that<br>
&lt;fantasai> miriam: We used the "custom property" spelling for locals and arugments, where really those are two different features.<br>
&lt;fantasai> miriam: I'm arguing that, for consistency, a custom property in a mixin should be like any other property. No reason to assume it's local.<br>
&lt;fantasai> miriam: if we want different spellings between custom properties and locals, it's the locals that should get a new spelling<br>
&lt;astearns> q?<br>
&lt;fantasai> miriam: Custom properties shouldn't need special syntax to make them be custom properties.<br>
&lt;fantasai> miriam: they already have their own syntax.<br>
&lt;astearns> ack lea<br>
&lt;fantasai> miriam: I don't think the consitency argument plays out the way you're saying<br>
&lt;fantasai> lea: +1 to everything miriam just said<br>
&lt;fantasai> lea: I'm not even convinced the similarity is helpful, they're so different.<br>
&lt;fantasai> lea: But in any case, the purpose of consistency is ergonomics. If ergonomics leans towards less consistency, then that's the right anwer.<br>
&lt;fantasai> lea: My understanding is that you can set locals outside @result if you declare them outside @result?<br>
&lt;fantasai> TabAtkins: nope<br>
&lt;fantasai> TabAtkins: Locals exist within the context of an executing mixin<br>
&lt;fantasai> lea: [missed]<br>
&lt;fantasai> lea: Argument about Chris Coyier ... he also thought that the first result property wins, so might be a mental model disconnect there<br>
&lt;astearns> s/[missed]/we re-used custom properties for locals and threw away some of their behavior<br>
&lt;fantasai> lea: But also authors will be biased towards supporting the current design because they want the thing<br>
&lt;fantasai> lea: That's why you don't give people "current design and modification" but "two equal options" to get their opinion<br>
&lt;TabAtkins> fantasai: +1 to Lea and Miriam's comments about ergonomics and consistency<br>
&lt;TabAtkins> fantasai: I wanted to respond to Roman's comment about reusing @local in other contexts<br>
&lt;TabAtkins> fantasai: this isn't a namesapcing mechanism, this is a different kind of construct<br>
&lt;TabAtkins> fantasai: if we reused it, it wouldn't be a namespacing mechanism<br>
&lt;lea> s/ lea: [missed]/ lea: one of the primary advantages of custom properties is their dynamic scoping and their cascading &amp; inheritance. So we're basically reusing custom properties and throwing away the best things about them?/<br>
&lt;fantasai> astearns: not hearing consensus<br>
&lt;fantasai> TabAtkins: Options are spec as-is, or spell locals in some other way.<br>
&lt;fantasai> TabAtkins: Doesn't seem like anyone wants to auto-insert @result<br>
&lt;lea> I also think it's ok if L1 doesn't have extra locals (in addition to the arguments)<br>
&lt;fantasai> astearns: Other ideas?<br>
&lt;astearns> ack fantasai<br>
&lt;Zakim> fantasai, you wanted to respond to kizu and to<br>
&lt;TabAtkins> fantasai: Remind me what happens if you have multiple @results<br>
&lt;TabAtkins> TabAtkins: last one (not in a false conditional) wins<br>
&lt;TabAtkins> fantasai: so without @result, all of the contents would be output<br>
&lt;TabAtkins> fantasai: I think it would be really obvious what's happening then<br>
&lt;lea> q+<br>
&lt;astearns> ack lea<br>
&lt;fantasai> fantasai: You output everything, except what's hidden by @local.<br>
&lt;fantasai> fantasai: That seems nice.<br>
&lt;TabAtkins> TabAtkins: (note that most at-rules in CSS are last-wins)<br>
&lt;fantasai> lea: I think we could ship L1 without locals.<br>
&lt;fantasai> lea: And also, since we're rethinking this<br>
&lt;fantasai> lea: if locals are like custom properties, then let's make them behave like custom properties<br>
&lt;lea> s/L1 without locals/L1 without extra locals/<br>
&lt;miriam> (we do have some at-rules that combine)<br>
&lt;fantasai> lea: (we definitely keep arugments though)<br>
&lt;fantasai> TabAtkins: Dropping locals doesn't make anything simpler<br>
&lt;fantasai> TabAtkins: Locals themselves, it's not complicated. Just relation to return value is what we need to fix.<br>
&lt;fantasai> s/fix/figure out/<br>
&lt;fantasai> TabAtkins: Atm I would object to spelling differently from @function, so let's go back to issue for now.<br>
&lt;lea> looks like we'll need another mixins breakout soon<br>
</details>


-- 
GitHub Notification of comment by css-meeting-bot
Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/13524#issuecomment-4173368648 using your GitHub account


-- 
Sent via github-notify-ml as configured in https://github.com/w3c/github-notify-ml-config

Received on Wednesday, 1 April 2026 22:36:20 UTC