Re: [csswg-drafts] [mediaqueries-5][css-conditional-5][css-mixins-1] Order dependent rules and adopted stylesheets (#13041)

The CSS Working Group just discussed `[mediaqueries-5][css-conditional-5][css-mixins-1] Order dependent rules and adopted stylesheets`, and agreed to the following:

* `RESOLVED: Revert earlier resolution about order-dependence, instead make @custom-media/supports and @mixins use the mechanism in this issue to resolve name collisions`

<details><summary>The full IRC log of that discussion</summary>
&lt;fantasai> scribe+<br>
&lt;fantasai> TabAtkins: Last discussed in Paris last year, a lot of rules we are adding apply during early style sheet processing and can have interesting effects on style sheet processing like imports.<br>
&lt;fantasai> TabAtkins: How do we deal with collisions in names?<br>
&lt;fantasai> TabAtkins: We have to resolve to one of potentially multiple named declarations.<br>
&lt;fantasai> TabAtkins: Plus, they could be inside conditional rules<br>
&lt;fantasai> TabAtkins: and then can chain things and create cycles<br>
&lt;fantasai> TabAtkins: In Paris, we decided that these sorts of rules have strict order dependence<br>
&lt;fantasai> TabAtkins: They use the named rule that is the most recently defined (last) *at that point*<br>
&lt;fantasai> TabAtkins: A rule after the reference will be ignored.<br>
&lt;fantasai> TabAtkins: So definition of certain names can different definitions depending on where they are<br>
&lt;fantasai> TabAtkins: This is very novel. Doesn't match how CSS works in any other sense.<br>
&lt;fantasai> TabAtkins: It solved the problem, but now authors have to learn a new model of how things work.<br>
&lt;fantasai> TabAtkins: Can't rely on global "last wins" rule that existing concepts use<br>
&lt;dbaron> (this also seems weird from a mutating-CSSOM-later perspective)(<br>
&lt;fantasai> TabAtkins: Anders has been working on a way to restore name conflict handling more closely to the "last wins" rule<br>
&lt;fantasai> TabAtkins: The exact details are maybe too complicated to explain, but details in this issue.<br>
&lt;emilio> q+<br>
&lt;astearns> zakim, open queue<br>
&lt;Zakim> ok, astearns, the speaker queue is open<br>
&lt;astearns> q+ emilio<br>
&lt;fantasai> TabAtkins: You do a first pass to determine the dependencies of a rule.<br>
&lt;fantasai> TabAtkins: Using that graph, you resolve any cycles.<br>
&lt;fantasai> TabAtkins: Just like variables, we kill the cycle and all its definitions<br>
&lt;fantasai> TabAtkins: Now with the set of valid definitions, figure out which is last one, and evaluate conditions properly.<br>
&lt;fantasai> TabAtkins: The precise details are complex, but not too hard to spec.<br>
&lt;fantasai> TabAtkins: Emilio reviewed and said while it's harder than order-dependent version, it's more reasonable<br>
&lt;fantasai> TabAtkins: We also like it because it avoids learning a new conflict resolution rule<br>
&lt;fantasai> TabAtkins: And also works better with shadow DOM.<br>
&lt;fantasai> TabAtkins: More CSSy = better.<br>
&lt;kizu> q+<br>
&lt;fantasai> TabAtkins: If people trust Anders and Emilio, would like to undo Paris resolution and adopt this one instead.<br>
&lt;astearns> ack emilio<br>
&lt;fantasai> emilio: Agree it's a better model. But some drawbacks.<br>
&lt;fantasai> emilio: Some things change behavior subtly depending on whether using a custom thing or not<br>
&lt;TabAtkins> `@import "URL" supports(foo: bar)`<br>
&lt;fantasai> emilio: For example, @import with supports(), if the browser doesn't support, it won't even try to load<br>
&lt;TabAtkins> ^^^ defined to *not load* the URL if the supports() fails<br>
&lt;fantasai> emilio: But with this setup we do need to load them, because the custom media definition might be inside the stylesheet itself.<br>
&lt;fantasai> emilio: I don't see a good way to work around this.<br>
&lt;fantasai> emilio: Other than scoping the names, which we didn't want to do.<br>
&lt;fantasai> emilio: Not sure there's another user-visible change here.<br>
&lt;TabAtkins> but if it's `@custom-media --foo (foo: bar); @import "URL" supports(--foo);`, we have to early-load it because we don't know the custom media yet<br>
&lt;fantasai> anders: Yeah, that's the main downside. We'd have to load that import unconditionally so we can hunt for cycles in there.<br>
&lt;TabAtkins> (Sorry, @custom-supports there)<br>
&lt;fantasai> anders: I think the drawback there is worth it.<br>
&lt;fantasai> emilio: Yeah, I think I agree with making that tradeoff.<br>
&lt;fantasai> emilio: We have to do a bit more work, but the result is uncontroversially better with this proposal.<br>
&lt;lea> q?<br>
&lt;fantasai> anders: It doesn't change behavior. It just changes loading.<br>
&lt;fantasai> emilio: But if you have layers and stuff?<br>
&lt;fantasai> emilio: I guess those are conditionally defined so it's ok.<br>
&lt;fantasai> emilio: But the loading behavior is somewhat observable.<br>
&lt;fantasai> emilio: But in the end, not observable.<br>
&lt;fantasai> anders: If we discover a real behavior difference here, then we should revisit.<br>
&lt;fantasai> emilio: Maybe test unconditionally loading all @imports and see if there's a change.<br>
&lt;astearns> ack kizu<br>
&lt;fantasai> kizu: Will later mixin win for all @apply, or will you define a mixin and the use it and then define another mixin with the same name and use that?<br>
&lt;fantasai> TabAtkins: You will always use the last declared name<br>
&lt;fantasai> kizu: This is a huge change for mixins. And big issue for library authors if we don't have any lexical scoping.<br>
&lt;fantasai> kizu: When operating on DOM things, we have specificity, etc. to scope things in the tree.<br>
&lt;fantasai> kizu: But mixins and functions have no scoping.<br>
&lt;fantasai> kizu: In CSS, we already have this problem with @keyframes etc.<br>
&lt;fantasai> kizu: But for mixins and functions, we need a way to lexically scope things if we do this<br>
&lt;emilio> q+<br>
&lt;fantasai> kizu: Because otherwise if I use a --foo function, and someone else defines a --foo function, my code will break.<br>
&lt;fantasai> TabAtkins: @function isn't affected by this, it takes the last definition always anyway.<br>
&lt;fantasai> TabAtkins: This makes @mixin work the same way as @function.<br>
&lt;fantasai> TabAtkins: You *can* use layers. You can make sure you're layering.<br>
&lt;fantasai> fantasai: But then you have the opposite problem which is your stuff breaks their stuff.<br>
&lt;fantasai> TabAtkins: All of our name-defining at-rules have the same problem. So they should have the same solution.<br>
&lt;astearns> ack dbaron<br>
&lt;andruud3> q+<br>
&lt;fantasai> dbaron: I haven't dug into details, but want to make the general point that performance characteristics are behavior.<br>
&lt;fantasai> dbaron: Even if what rules match and values of properties are don't change, performance characteristics do matter to developers and users.<br>
&lt;fantasai> dbaron: Maybe it's the right tradeoff, but I don't think we should say "oh we're not changing behavior" here.<br>
&lt;fantasai> dbaron: If you can sacrifice something else to get that performance back, might want to do that.<br>
&lt;romain> Authors can make this tradeoff themselves. They can not use a custom supports<br>
&lt;fantasai> TabAtkins: Problem is it's a cycle detection issue. We need to know what's inside the custom supports query.<br>
&lt;romain> And use a regular supports query instead<br>
&lt;fantasai> TabAtkins: We will retain the loading behavior, aka not loading, if you don't use custom supports queries.<br>
&lt;emilio> fantasai: I think I agree with dbaron that right now people assume if I use supports on an @import we assume it isn't loading<br>
&lt;lea> +1 fantasai<br>
&lt;emilio> ... and not doing a conditional loading themselves<br>
&lt;emilio> ... I don't think the fact I'm using an aliasing mechanism...<br>
&lt;emilio> ... people are not going to realize that perf characteristics change<br>
&lt;emilio> ... I think that maybe we could make these things not work outside the @improt<br>
&lt;emilio> ... @import<br>
&lt;emilio> q+<br>
&lt;fantasai> s/maybe we could/it would be better to/<br>
&lt;emilio> ... +1 to kizu's concerns about scoping<br>
&lt;dbaron> was fantasai's "these things" specifically about custom supports?<br>
&lt;astearns> ack emilio<br>
&lt;fantasai> yeah<br>
&lt;astearns> ack fantasai<br>
&lt;fantasai> emilio: Not being able to use custom supports queries outside of @import, it makes it's inconsistent.<br>
&lt;kizu> (Linking the scoping/namespacing issue: https://github.com/w3c/csswg-drafts/issues/11798)<br>
&lt;fantasai> TabAtkins: Link with supports also wouldn't load<br>
&lt;fantasai> emilio: If the @import was not conditional on supports.<br>
&lt;TabAtkins> emilio: if the @import wasn't conditional, it should definitely let you define custom-media/etc outside of the import. common design system thing<br>
&lt;fantasai> emilio: Unconditional @import is a strong use case. If you have @import "design-system-thing-defining-breakpoints"; should work outside the @import<br>
&lt;fantasai> emilio: Making the conditional support query ...<br>
&lt;fantasai> emilio: If you scope the names to the @import based on whether ...<br>
&lt;bramus> scribe+<br>
&lt;lea> q?<br>
&lt;bramus> fantasai: if you define a named supports query inside a imported style sheet and then use that named query to condition the loading of the stylesheet<br>
&lt;lea> q+<br>
&lt;bramus> TabAtkins: you woul dnormallly condition another stylesheet - otherwise its cyclic<br>
&lt;bramus> fantasai: wha tdo we do now?<br>
&lt;bramus> emilio: now it doesnt exist<br>
&lt;bramus> … with the paris behavior, if the condition was not defined, it doesnt match and you dont load the import<br>
&lt;bramus> … but it has the other weird thing if then somebody overwrites the condition later on, it doesnt work<br>
&lt;bramus> … and so with the behavior that andruud is proposing you need to go inside the import to catch cycles<br>
&lt;bramus> … if you conditionally define something inside the import &lt;missed> you need to catch that<br>
&lt;bramus> … as it may affect the conditition on the import<br>
&lt;bramus> … dont see way to prevent that wihtout scoping them to the stylesheet, but that might be bad<br>
&lt;bramus> … because a condition might then no longer work<br>
&lt;romain> q+<br>
&lt;bramus> … the loading is the least bad of the option<br>
&lt;romain> q-<br>
&lt;fantasai> bramus: can we disallow using custom supports to condition an @import?<br>
&lt;bramus> TabAtkins: &lt;missed><br>
&lt;bramus> emilio: disallowing cistom supports inside supports() would be unfortunate<br>
&lt;bramus> TabAtkins: it would be wrid to disallow this because the loading characteristics arent ideal<br>
&lt;bramus> fantasai: when they are not true<br>
&lt;bramus> emilio: &lt;missed><br>
&lt;bramus> fantasai: most of the time you expect them to be false some of the time at least<br>
&lt;bramus> … it is increasingly true that they are not false<br>
&lt;bramus> … lots of code that might be ???<br>
&lt;bramus> emilio: or like negated supports condition<br>
&lt;bramus> fantasai: to load fallback styles<br>
&lt;bramus> TabAtkins: and this will behavior will make tha twork correctly<br>
&lt;bramus> … but means that if you dont need to get that content to load, youd still get network traffic<br>
&lt;bramus> fantasai: how does that interact with script?<br>
&lt;bramus> TabAtkins: JS libs dont have this sort of condition<br>
&lt;bramus> … you can execute a supports query in JS, bu twill be state of the thing at the time<br>
&lt;astearns> ack andruud<br>
&lt;romain> q+<br>
&lt;bramus> andruud: to respond to kizu. you have a better proposal for lexical scoping. order depending is poor substitute for it<br>
&lt;bramus> … only applies to few select ???, but you want a more generic thing<br>
&lt;bramus> … dont think its workth about thinking order dependence … ahve a much better proposal from you to consider<br>
&lt;bramus> kizu: the issue about namespacing (lexical scoping) would be nice to have it someehwere alongside functions and mixins, tha tway authors can use ??? would be greatto think about it in the same room<br>
&lt;bramus> … small note: if we scope this to a stylesheet, well have to have some way to scope it without ??? stylesheet. when some bundler unwraps it, they need to be able to scope things inside<br>
&lt;bramus> …  we need to have it without wrapping things int eh stylesheet<br>
&lt;astearns> ack lea<br>
&lt;bramus> TabAtkins: agree<br>
&lt;bramus> lea: do i understand correctly that these custom supports and media rules work in a last one wins fashion?<br>
&lt;bramus> emilio: after this change?<br>
&lt;bramus> lea: after<br>
&lt;bramus> TabAtkins: last valid one wins<br>
&lt;bramus> … or most poweful one (layers)<br>
&lt;bramus> lea: and these can be parsed before import, right?<br>
&lt;bramus> … could they come before @import?<br>
&lt;bramus> TabAtkins: yes, tha tis the intention<br>
&lt;lea> scribe+<br>
&lt;romain> that is more syntactic sugar, doesn't really change anything else, right?<br>
&lt;TabAtkins> yes, that's sugar<br>
&lt;lea> lea: If we are willing to relax parsing, do we even need a dedicated `supports()`, syntax, can't we just next the `@import` inside a regular `@supports {}` rule which also gives us more flexibility? I believe it hasn't been implemented anywhere yet?<br>
&lt;bramus> emilio: this is tangential ad doesnt fix the issue<br>
&lt;bramus> lea: but reduces the API surface<br>
&lt;bramus> emilio: increases<br>
&lt;bramus> TabAtkins: &lt;missed><br>
&lt;bramus> lea: will it still be true that @import starts loading before ??? is parsed?<br>
&lt;fantasai> https://caniuse.com/mdn-css_at-rules_import_supports<br>
&lt;astearns> s/???/the stylesheet/<br>
&lt;lea> lea: is the entire stylesheet going to be parsed before `@import` starts loading?<br>
&lt;bramus> TabAtkins: if you make an @import condtioan on custom supports, will have same behavior as making it depending on MQ<br>
&lt;astearns> q?<br>
&lt;lea> lea: Because otherwise a later rule can override it<br>
&lt;bramus> … only change is you have  a suppports condition that is not custom: we evaluate immedaiately and might skip load entirely<br>
&lt;bramus> lea: and then issue is what happens if you load a stylesheet tha toverrides the custom supports condition<br>
&lt;lea> lea: so the issue is cycles when you load a stylesheet that cancels its own loading?<br>
&lt;bramus> TabAtkins: then its cyclic<br>
&lt;bramus> … if it was true and then false, then …<br>
&lt;bramus> emilio: no, not inside<br>
&lt;bramus> … afterwards<br>
&lt;bramus> lea: both<br>
&lt;bramus> TabAtkins: we have to undocntiaily load, but might not apply<br>
&lt;bramus> lea: (thinks)<br>
&lt;bramus> … what are proposed solutions? load and ignore?<br>
&lt;lea> lea: so implementation aside, conceptually what is the right solution? It is applied or not?<br>
&lt;bramus> TabAtkins: already have disallows custom supports on @import entirely or chang ebheabior ntirely to lexcailly scope them, or change the loading behavior (as prposed here)<br>
&lt;bramus> emilio: another proposal could be to always do th eload, even if the support fails<br>
&lt;bramus> TabAtkins: seems worse<br>
&lt;bramus> emilio: for completeness, would be consistent<br>
&lt;bramus> TabAtkins: that fails david’s loading behavior is important stance<br>
&lt;bramus> lea: need to think about this more<br>
&lt;astearns> ack romain<br>
&lt;bramus> romain: this proposal is a lot better than what is originally in the spec<br>
&lt;bramus> … need to make a tradeoff in some cases<br>
&lt;bramus> … also wonder how many authors will use custom queries in @import rules<br>
&lt;dbaron> agree that the new proposal is better<br>
&lt;fantasai> +1 romain<br>
&lt;bramus> … custom queries will be popular in style rules, but in import rules … would be fine with disallowing entirely<br>
&lt;bramus> +1<br>
&lt;bramus> emilio: custom supports can kinda buy, but custom media …<br>
&lt;bramus> … you are suggesting to disallow custom supports<br>
&lt;bramus> … if it suddenly didnt work …<br>
&lt;bramus> romain: easier to explain and discover than th eloading behavior for authors<br>
&lt;bramus> emilio: not sure<br>
&lt;bramus> … feels like adding a fallback for old browser and never test so would remain broken<br>
&lt;bramus> TabAtkins: very vali<br>
&lt;bramus> … if you are loading a polyfill<br>
&lt;bramus> … you wont test<br>
&lt;bramus> … alright to have that page be slower<br>
&lt;bramus> emilio: might berak modern browsers as well<br>
&lt;bramus> TabAtkins: that is the tradeoff: all browsers or only older browsers<br>
&lt;bramus> romain: but authors can still optoimize<br>
&lt;bramus> fantasai: I think we need  to put this in an advisement box in the spec. LIke “if you try to use on @import it wont block loading”<br>
&lt;lea> q+<br>
&lt;bramus> TabAtkins: put it there and in the @import definition<br>
&lt;bramus> fantasai: yes<br>
&lt;astearns> ack lea<br>
&lt;bramus> lea: wether it loads (http request) and apply is sepaarte thing<br>
&lt;bramus> … if we allow custom supports and they are never true, there is no reason to kick off loading<br>
&lt;bramus> … if it becomes false later then we can unapply<br>
&lt;bramus> TabAtkins: we could ??? and then preserve dont load as it fails the supports query<br>
&lt;bramus> … other is always load, but only apply when it needs to<br>
&lt;bramus> lea: feels like penalzing older browsers<br>
&lt;bramus> … could be may beas “if this every becomes true then fetch it”<br>
&lt;bramus> TabAtkins:  we dont have a sort of pending load right now<br>
&lt;bramus> … stylesheets load immediately<br>
&lt;bramus> emilio: not really. reason to undocntoiaally load MQ gated ones is FOUC<br>
&lt;bramus> … with supports() you know  you are never applying<br>
&lt;emilio> The interesting case would be: `@supports "table-layout.css" not supports(display: grid);` vs `@supports "table-layout.css" not supports((--grid-layout));`<br>
&lt;bramus> TabAtkins: if you conditionally load, and then it becomes true, you’ll have to wait on the network<br>
&lt;bramus> lea: seems like an acceptable tradeoff<br>
&lt;bramus> TabAtkins: that is what we made with print media stylesheets always loading<br>
&lt;bramus> … because when you do print, we dont want to wait on the network<br>
&lt;bramus> lea: that is different ; user activitiy … can press print at any point<br>
&lt;bramus> … the @supports usually dont hcnage<br>
&lt;bramus> TabAtkins: but when they do, other stuff might depend on it<br>
&lt;bramus> lea: reallisticly the ar enot equivalent<br>
&lt;bramus> emilio: you could have a stylesheet load slower<br>
&lt;bramus> astearns: not gonna get to that today … can take a resolutoin fo r??? and leave open how we adapt how import behaves given that we are removing the order dependence<br>
&lt;bramus> TabAtkins: mixins, custom media, custom suupport … and potentially future things<br>
&lt;bramus> lea: could someone outline the proposed resolution?<br>
&lt;bramus> TabAtkins: there is no longer is an order dependence<br>
&lt;bramus> … last one defined a true condition wins<br>
&lt;bramus> astearns: and we are in agreement that that is better<br>
&lt;TabAtkins> proposed resolution: Revert earlier resolution about order-dependence, instead make @custom-media/supports and @mixins use the mechanism in this issue to resolve name collisions<br>
&lt;bramus> emilio: so we area ccepting the proposal<br>
&lt;bramus> andruud: and then details about support-affected details TBD<br>
&lt;TabAtkins> TBD @import supports() with a custom supports<br>
&lt;bramus> astearns: objections?<br>
&lt;bramus> RESOLVED: Revert earlier resolution about order-dependence, instead make @custom-media/supports and @mixins use the mechanism in this issue to resolve name collisions<br>
&lt;dholbert> scribenick: dholbert<br>
</details>


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


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

Received on Thursday, 29 January 2026 19:15:23 UTC