- From: CSS Meeting Bot via GitHub <noreply@w3.org>
- Date: Wed, 02 Jul 2025 16:03:11 +0000
- To: public-css-archive@w3.org
The CSS Working Group just discussed ``[css-cascade-6] `&` matching inside the `@scope`, and its interaction with `:scope` ``. <details><summary>The full IRC log of that discussion</summary> <fantasai> miriam: Inside of @scope, & and :scope do similar things<br> <fantasai> miriam: but slightly different<br> <fantasai> miriam: partially because of how nesting and scoping were designed<br> <fantasai> miriam: wanted & to behave consistently<br> <fantasai> miriam: so it refers to the scope root<br> <fantasai> miriam: *selector*<br> <fantasai> miriam: and takes on the specificity of that selector<br> <fantasai> miriam: :scope is a bit different<br> <fantasai> miriam: it has specificity of a pseudo-class, and matches exactly one element -- the root element of the scope<br> <fantasai> miriam: it's not a stand-in for the selector, it targets a specific element<br> <fantasai> miriam: question was if those should be more the same in some way<br> <fantasai> kizu: I proposed two options, I think 2nd is more clear<br> <fantasai> kizu: If you're inside a scope, and you only mention &, then you are mentioning that specific root node, same as scope<br> <fantasai> kizu: but it might be weird if you have two &<br> <fantasai> miriam: You wouldn't be able to do & + &<br> <fantasai> miriam: My tendency here is to keep it how it is, because I think all of the solutions are potentially confusing<br> <fantasai> miriam: and at least this one is consistent with how & works in other places<br> <fantasai> miriam: but open to discussion<br> <emilio> q+<br> <fantasai> astearns: Roman, your main concern is author mistakes?<br> <ydaniv> I think +1 to kizu's choice<br> <fantasai> kizu: yeah<br> <fantasai> kizu: Also, if it's an &, is it equal to & in scope?<br> <fantasai> kizu: otherwise where does the implicit as :scope go?<br> <fantasai> kizu: In my tests, this &, matched something outside of the scope<br> <fantasai> kizu: so you could target context outside the scope, and it could match an element inside the scope<br> <fantasai> kizu: it's a weird interaction<br> <fantasai> kizu: is it the same as &, where it still matches scope root; or if not, should it match anything outside the scope?<br> <fantasai> miriam: It's a scoped selector, so matching anything outside would be a bug<br> <kizu> `& h1`<br> <fantasai> miriam: it's not exactly scope ... matching anything that that selector matches as long as it is in the scope<br> <fantasai> miriam: So scope doesn't necessarily end where it starts<br> <fantasai> kizu: You can inside a scope you can make adjustment on element outside the scope<br> <fantasai> kizu: because you only check whether the subject of the selector is contained by the scope, not other elements in the selector<br> <fantasai> kizu: If we do inside a scope ...<br> <kizu> `@scope … { &:hover { … } }`<br> <fantasai> kizu: Do we match only on :hover of the :scope, or will it match something outside the scope?<br> <fantasai> kizu: You could argue both ways, and Safari and chrome differ last time I tested<br> <kizu> `@scope … { &:hover :scope { … } }`<br> <fantasai> emilio: :hover case shouldn't match anything outside the scope<br> <fantasai> kizu: here's a better example<br> <fantasai> miriam: is that confusing though? We've said explicitly where the scope is<br> <fantasai> kizu: There was a difference in implementation, so we should clarify either way<br> <fantasai> miriam: More confusing if you did &:hover p<br> <astearns> ack emilio<br> <fantasai> emilio: Can you remind me what the implicit selector meant?<br> <emilio> `& > foo`, `> foo`?<br> <matthieud> @scope … { &:hover :scope { … } } Can this actually match something ?<br> <fantasai> emilio: If you don't write an ampersand, it's :scope right?<br> <fantasai> miriam: yes<br> <fantasai> emilio: I think that difference is very confusing.<br> <fantasai> emilio: To me it would make sense if & was always :scope<br> <fantasai> emilio: Not sure how others feel about that<br> <fantasai> kizu: Currently everyone is doing the same, so could close it no change, because at least it's interoperable right now<br> <fantasai> miriam: Emilio, would you expect them to have the same specificity? or different specificity but matching the same element<br> <fantasai> emilio: What do we do for nesting, we add the specificity, right?<br> <fantasai> emilio: So I would expect specificity here to work the same<br> <fantasai> emilio: ... it's not great<br> <astearns> ack ydaniv<br> <fantasai> ydaniv: In terms of specificity, I think the fact that they do match, to me it's intuitive<br> <fantasai> ydaniv: Authors still see it as appending stuff<br> <fantasai> ydaniv: Emilio's example, that the have the same specificity<br> <fantasai> astearns: You don't see an issue in changing the & specificity based on location?<br> <fantasai> ydaniv: If it's the root of the scope, and & matches an implicit :scope selector ...<br> <fantasai> ydaniv: so question is whether the scope-start selector or implicitly just :scope?<br> <fantasai> emilio: I think there are 3 possible answers. We have 3 related selectors<br> <fantasai> emilio: There's <scope-start>, i.e. the selector in the @scope () prelude<br> <fantasai> emilio: The there's :scope<br> <fantasai> emilio: And then there's :where(:scope)<br> <fantasai> emilio: Right now we're using all three of them<br> <fantasai> emilio: & means the first<br> <fantasai> emilio: implicit selector means :where(:scope), right?<br> <fantasai> emilio: and then you can type :scope<br> <fantasai> emilio: It's all fairly confusing to me, that they do different things<br> <fantasai> emilio: than a nested selector<br> <fantasai> emilio: That implicit nested selectors behave differently than explicit nested selectors<br> <fantasai> <fantasai> +1<br> <fantasai> miriam: Part of what creates that is that :scope has specificity and & has specificity and they're different<br> <fantasai> miriam: so what should implicit do?<br> <fantasai> emilio: Couldn't we define & to be :where(:scope), so at least it's consistent with implicit just as in nested?<br> <fantasai> miriam: The @scope rule on its own doesn't add specificity, so we could say reasonably, the & representing the parent is zero since scope rule has zero specificity<br> <fantasai> emilio: That also explains nested selectors within @scope<br> <romain> q+<br> <fantasai> emilio: @scope { foo ... } that's same as @scope { :where(:scope) foo ... } right?<br> <fantasai> miriam: That brings us back to Roman's question of whether & matches the scope root, or other elements that happen to match the same selector<br> <fantasai> emilio: Make it match the scope root<br> <kizu> > The & selector is defined to represent the selector representing the scoping root (the <scope-start> selector), or else :scope if no selector was specified.<br> <fantasai> miriam: that would be different from other places where we represent the enclosing selector<br> <fantasai> kizu: & is designed to represent the selector of the scoping root, not the scoping root<br> <fantasai> kizu: Right now they could consider both the specificity of the scoping root *and* ???<br> <fantasai> kizu: So maybe we adjust to make it represent the scoping root<br> <fantasai> miriam: So proposal is to make & represent :where(:scope)<br> <fantasai> kizu: Yes. But we will need to see if it will not break something.<br> <fantasai> emilio: It's behavior change either way<br> <fantasai> miriam: I'm ok with this change<br> <fantasai> kizu: I think it would be better<br> <astearns> ack fantasai<br> <astearns> q+<br> <emilio> ack fantasai<br> <astearns> ack romain<br> <fantasai> romain: I'm unsure if removing specificity here is the right call<br> <fantasai> romain: I think authors will expect the specificity, and it will be weird to remove it<br> <emilio> q+<br> <fantasai> romain: Adding selectors makes things more specific. Not adding specificity when using & feels weird to me.<br> <fantasai> miriam: Even though scope root selector adds no specificity by default?<br> <fantasai> romain: but :scope has specificity, it's only wrapping in an at-rule that doesn't have specificity<br> <fantasai> miriam: Are you saying have it be the same as :scope?<br> <fantasai> romain: Maybe.<br> <fantasai> romain: Writing a selector and having it produce zero specificity feels weird to me.<br> <fantasai> romain: I don't think there's any other selector that behaves like that<br> <fantasai> astearns: I'm also a little concerned about difference of & in @scope vs nesting<br> <fantasai> astearns: but also, is there a way to get the specificity of the @scope prelude, if we make this change?<br> <fantasai> miriam: No<br> <fantasai> matthieud: No, and I think that was the reason for this. It allows authors to opt into this specificity<br> <astearns> ack astearns<br> <fantasai> miriam: The way we specced it is the most powerful, because you get all the options. But also the most confusing, because you have all the options.<br> <fantasai> astearns: Do we believe authors will no longer need that option?<br> <emilio> fantasai: I think the reason it's confusing is because the way specificity is introduced here is implicit in the syntax in a non-obvious way<br> <emilio> ... if we were clearer about what specificity different things have it'd be less confusing<br> <kizu> This is what we have right now:<br> <kizu> - `@scope (article) { h1 {} }` — 0.0.1<br> <kizu> - `@scope (article) { & h1 {} }`— 0.0.2<br> <kizu> - `@scope (article) { :scope h1 {} }` — 0.1.1<br> <emilio> fantasai: I think the problem is that it is so implicit<br> <fantasai> miriam: It's implicit, but it's also following existing rules.<br> <fantasai> miriam: The implicit one is the only new one<br> <astearns> :scope-selector<br> <fantasai> astearns: if we make this change, and then we do find that ppl need access to the prelude selector's specificity, what are our options?<br> <fantasai> astearns: do we need a new pseudo, that targets the scope selector?<br> <fantasai> kizu: Also some proposal to have a scope-end selector, so adding scope-start wouldn't be unreasonable<br> <astearns> ack emilio<br> <fantasai> emilio: I understand why we have the 3 options. But thing that feels really odd is that even if you explicitly nest something, e.g. using child combinator, it doesn't behave the same as & in child<br> <fantasai> emilio: it differs from nesting in a really subtle way<br> <fantasai> emilio: can do anything, but feels odd to me ... I understand why we don't want @scope { } to increase specificyt<br> <fantasai> emilio: adding specificity of :scope, that would be a problem<br> <fantasai> emilio: but it's not great!<br> <fantasai> emilio: I'm ok even with no change, but it's very weird behavior<br> <fantasai> emilio: explaining it to ppl is going to be very "fun"<br> <fantasai> miriam: Other part<br> <fantasai> miriam: Does & match things other than scope root?<br> <emilio> q+<br> <astearns> ack fantasai<br> <emilio> fantasai: I think there's 3 ways that could go<br> <emilio> ... we could say & matches things other than the scope root anywhere<br> <emilio> ... that it only matches the scope root<br> <emilio> ... or it matches things that match the scope root but only inside the scope<br> <emilio> ... If yo do `foo bar` inside `@scope` can foo match inside the scope?<br> <kizu> Related post: https://blog.kizu.dev/scope-selector-nuance/ :)<br> <emilio> miriam: no because of the implicit scope selector, so only if you add `&` or `:scope` somewhere<br> <fantasai> emilio: That implicit nesting means that ..<br> <emilio> `@scope (..) { foo bar { ... } }` is basically `:where(:scope) foo bar { ... }`<br> <fantasai> :where(:scope) foo bar, foo:where(:scope) bar, foo :where(:scope) bar ?<br> <fantasai> miriam: No, it has the implicit `:where(:scope)` at the front<br> <fantasai> miriam: unless you put the & somewhere else, so same as scope<br> <fantasai> fantasai: So & represents the scope-start selector + :where(:scope) ?<br> <fantasai> kizu: that's the question<br> <emilio> emilio: no, only scope-start<br> <emilio> fantasai: what miriam said is that if it doesn't represent `:scope` it can expand the scope<br> <kizu> `&:hover :scope`<br> <emilio> miriam: it can match outside of the scope<br> <emilio> emilio: because `&` prevents the implicit `:where(:scope)` from getting inserted<br> <astearns> q?<br> <astearns> ack emilio<br> <fantasai> astearns: Should we go back to Miriam's idea of choosing what & matches, before we decide on specificity?<br> <fantasai> astearns: I kinda like the idea that it can only match the scope root.<br> <emilio> q+<br> <fantasai> astearns: idea of matching other things inside the scope root seems weird to me<br> <fantasai> emilio: I think it's fine, but pretty tied to the specicificity question<br> <fantasai> emilio: would be nice not to define it as something magic<br> <fantasai> emilio: we've explained it as ??<br> <fantasai> emilio: be nice to say it's just :where(:scope) or :scope, or ...<br> <matthieud> s/??/:is(...)<br> <fantasai> emilio: Another option would be & doesn't avoid injecting that implicit scope selector, that might be weird in other ways<br> <fantasai> emilio: and doesn't quite mean that it only matches scope root, just means selector can't escape the scope root<br> <fantasai> emilio: which btw, is there a way of explicitly escaping the scope root?<br> <fantasai> emilio: other than :scope(:not):scope<br> <romain> <div class="row"><br> <romain> ...<br> <romain> <div class="row"><br> <romain> @scope (.row) {<br> <romain> & :scope { ... }<br> <romain> }<br> <romain> Is this the question at hand?<br> <romain> That & is ".row" and therefor this selector can match?<br> <emilio> s/:scope(:not):scope/:where(:scope, :not(:scope))` (or so)<br> <emilio> s/:scope(:not):scope/:where(:scope, :not(:scope))/ (or so)<br> <fantasai> astearns: what should we do?<br> <matthieud> (The subject can never escape the scope though, whatever the selector of the scoped rule be)<br> <fantasai> miriam: maybe write out all the options and take it back to the issue?<br> <fantasai> astearns: Questions we have are 1. What exactly does the & represent. Seems like we have 4 options.<br> <fantasai> astearns: and then 2. What specificity is added when you use an &<br> <fantasai> astearns: Do we have just 2 options here?<br> <fantasai> miriam: Emilio wanted it to match answer to first question<br> <fantasai> astearns: Depending on answer to first question, specificity of & inside @scope may or may not match how it works in nesting<br> <fantasai> miriam: since defining as specificity of parent selector, there's at least a match there<br> <fantasai> emilio: Third question, should an & keep preventing the inclusion of the implicit :scope at the start of the selector<br> <fantasai> astearns: which also may be informed by what we have it represent<br> <fantasai> emilio: Right. if we choose that it is :scope or :where(:scope)<br> <fantasai> matthieud: Different behavior for nesting and @scope<br> <fantasai> emilio: I think my preference would be to define the parent selector as :where(scope)<br> <fantasai> emilio: i.e. make & as :where(:scope)<br> <fantasai> emilio: then it's like nesting, you always unconditionally add it unless it's already existing somewhere else<br> <fantasai> emilio: It does lose the scope-start specificty, but I think that's OK<br> <fantasai> emilio: because that's the behavior you get without &<br> <kizu> +1 to make it :where(:scope)<br> <fantasai> miriam: [missed]<br> <fantasai> emilio: I think that would be the more consistent solution<br> <fantasai> emilio: to say that & is :where(:scope)<br> <fantasai> astearns: My concern with merely doing that is that this issue.. nothing gets done<br> <fantasai> astearns: We could resolve that & matches :where(:scope) and then allow the "being wrong on the internet" effect to elicit responses?<br> <fantasai> miriam: I think it already worked to list out the options, and here we are back to take a resolution<br> <fantasai> astearns: Anyone with concerns wrt & behaving as :where(:scope)?<br> <fantasai> astearns: Like more time to work through examples etc.?<br> <fantasai> andruud: It remains to be seen whether we can actually do it, since @scope has shipped<br> <astearns> ack emilio<br> <fantasai> emilio: Not yet shipping in FF<br> <emilio> fantasai: I think my suggestion would be to take a tentative resolution to give a chance to people not here<br> <emilio> ... or on vacation<br> <emilio> ... gives a bit more time to people not here<br> <emilio> +1<br> <kizu> +1<br> <fantasai> astearns: Ok, let's take a resolution and say that we will revisit in a week to confirm<br> <fantasai> PROPOSED: & in @scope behaves as :where(:scope). We will revisit this in 1 week's time.<br> <fantasai> fantasai: Can Miriam or someone else post a blog post or something, to see if anyone has comments?<br> <fantasai> fantasai: can be short, like 3 paragraphs + point to issue<br> <fantasai> miriam and roman are maybe going to try<br> </details> -- GitHub Notification of comment by css-meeting-bot Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/9740#issuecomment-3028423633 using your GitHub account -- Sent via github-notify-ml as configured in https://github.com/w3c/github-notify-ml-config
Received on Wednesday, 2 July 2025 16:03:13 UTC