- From: Dael Jackson <daelcss@gmail.com>
- Date: Wed, 2 Jul 2025 19:33:15 -0400
- To: www-style@w3.org
========================================= These are the official CSSWG minutes. Unless you're correcting the minutes, please respond by starting a new thread with an appropriate subject line. ========================================= Scope Breakout -------------- - RESOLVED: Close no change (Issue #12418: Should/can relative selectors be allowed un-nested) - The proposed resolution from the call for issue #9740 (`&` matching inside the `@scope`, and its interaction with `:scope`) was `& in @scope behaves as :where(:scope)`. However, there were a lot of options and a lot of opinions, including some not represented on the call. Therefore, the team will hold on resolving for one week to give folks a chance to review and provide input. ===== FULL MEETING MINUTES ====== Agenda: https://github.com/orgs/w3c/projects/113/views/1 Present: Kevin Babbitt David Baron Justin Breiland Oriol Brufau Emilio Cobos Álvarez Yehonatan Daniv Matthieu Dubet Elika Etemad Anders Hartvoll Ruud Roman Komarov Romain Menke Alan Stearns Miriam Suzanne Scribe: fantasai Scribe's scribe: emilio Scope Breakout ============== Should/can relative selectors be allowed un-nested -------------------------------------------------- github: https://github.com/w3c/csswg-drafts/issues/12418 fantasai: Might've been useful to have Tab at this breakout miriam: This was raised by Lea wrt if a whole file is scoped on import miriam: If those items are relative selectors ... miriam: Should we allow relative selectors at every level of CSS including the root? miriam: If so, what would it mean? miriam: My leaning is that we don't need to do this miriam: Tab had some concerns with it miriam: For example, a relative selector with a child combinator is meaningless in relation to the root miriam: similarly ?? miriam: And normal descendant selector doesn't need to be relative until imported into a scope miriam: So not really combinators that are meaningful to do at the root level matthieud: what's the point of having relative top level selectors? matthieud: if we allow these is it only working when we `@import` scope() something? miriam: leaverou was expecting it to be relative to `:root` by default, but as tab pointed out that's not particularly useful miriam: so that's why I suggest no-change miriam: once we import in scopes I think people may want to do it but I don't think it makes sense to make it valid or not depending on the way it's important <kizu> +1 to no change matthieud: agree that they can just wrap in `:scope` miriam: or prefix each selector yeah fantasai: I think it's fine emilio: +1 fwiw astearns: if we're wrong and this is something people are going to use often astearns: and litter their sheets with `:scope`, how frustrating is that going to be? miriam: not sure who's going to complain about it miriam: but I think it's more explicit when you litter it with `:scope` miriam: so I think it's still the right choice miriam: it also raises the question of also allowing bare declarations in `@scope`, do we want to allow bare declarations in a css file? <kizu> +1, explicit > implicit emilio: You don't have to use :scope everywhere, right, can just wrap whole style sheet in :scope { emilio: so even if you wanted to do this, only need to add 2 lines of CSS ... and technically don't even need the closing bracket miriam: only needed for sibling or child combinator. Most styles are descendant combinators anyway miriam: and sibling is out of scope andruud: I'm happy with the discussion so far <romain> +1 to no change <emilio> +1 astearns: Proposed resolution, closed no change. Objections? RESOLVED: Close no change. `&` matching inside the `@scope`, and its interaction with `:scope` ------------------------------------------------------------------- github: https://github.com/w3c/csswg-drafts/issues/9740 miriam: Inside of @scope, & and :scope do similar things miriam: but slightly different miriam: partially because of how nesting and scoping were designed miriam: wanted & to behave consistently miriam: so it refers to the scope root miriam: *selector* miriam: and takes on the specificity of that selector miriam: :scope is a bit different miriam: it has specificity of a pseudo-class, and matches exactly one element -- the root element of the scope miriam: it's not a stand-in for the selector, it targets a specific element miriam: question was if those should be more the same in some way kizu: I proposed two options, I think 2nd is more clear kizu: If you're inside a scope, and you only mention &, then you are mentioning that specific root node, same as scope kizu: but it might be weird if you have two & miriam: You wouldn't be able to do & + & miriam: My tendency here is to keep it how it is, because I think all of the solutions are potentially confusing miriam: and at least this one is consistent with how & works in other places miriam: but open to discussion astearns: Roman, your main concern is author mistakes? kizu: yeah <ydaniv> I think +1 to kizu's choice kizu: Also, if it's an &, is it equal to & in scope? kizu: otherwise where does the implicit as :scope go? kizu: In my tests, this &, matched something outside of the scope kizu: so you could target context outside the scope, and it could match an element inside the scope kizu: it's a weird interaction kizu: is it the same as &, where it still matches scope root; or if not, should it match anything outside the scope? <kizu> `& h1` miriam: It's a scoped selector, so matching anything outside would be a bug miriam: it's not exactly scope ... matching anything that that selector matches as long as it is in the scope miriam: So scope doesn't necessarily end where it starts kizu: You can inside a scope you can make adjustment on element outside the scope kizu: because you only check whether the subject of the selector is contained by the scope, not other elements in the selector kizu: If we do inside a scope ... kizu: Do we match only on :hover of the :scope, or will it match something outside the scope? kizu: You could argue both ways, and Safari and chrome differ last time I tested emilio: :hover case shouldn't match anything outside the scope kizu: here's a better example <kizu> `@scope … { &:hover { … } }` <kizu> `@scope … { &:hover :scope { … } }` miriam: is that confusing though? We've said explicitly where the scope is kizu: There was a difference in implementation, so we should clarify either way miriam: More confusing if you did &:hover p <matthieud> @scope … { &:hover :scope { … } } Can this actually match something ? emilio: Can you remind me what the implicit selector meant? <emilio> `& > foo`, `> foo`? emilio: If you don't write an ampersand, it's :scope right? miriam: Yes emilio: I think that difference is very confusing. emilio: To me it would make sense if & was always :scope emilio: Not sure how others feel about that kizu: Currently everyone is doing the same, so could close it no change, because at least it's interoperable right now miriam: Emilio, would you expect them to have the same specificity? or different specificity but matching the same element emilio: What do we do for nesting, we add the specificity, right? emilio: So I would expect specificity here to work the same emilio: ... it's not great ydaniv: In terms of specificity, I think the fact that they do match, to me it's intuitive <fantasai> what matches what? ydaniv: Authors still see it as appending stuff ydaniv: Emilio's example, that the have the same specificity astearns: You don't see an issue in changing the & specificity based on location? ydaniv: If it's the root of the scope, and & matches an implicit :scope selector ... ydaniv: so question is whether the scope-start selector or implicitly just :scope? emilio: I think there are 3 possible answers. We have 3 related selectors emilio: There's <scope-start>, i.e. the selector in the @scope () prelude emilio: The there's :scope emilio: And then there's :where(:scope) emilio: Right now we're using all three of them emilio: & means the first emilio: implicit selector means :where(:scope), right? emilio: and then you can type :scope emilio: It's all fairly confusing to me, that they do different things emilio: than a nested selector emilio: That implicit nested selectors behave differently than explicit nested selectors <fantasai> +1 miriam: Part of what creates that is that :scope has specificity and & has specificity and they're different miriam: so what should implicit do? emilio: Couldn't we define & to be :where(:scope), so at least it's consistent with implicit just as in nested? 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 emilio: That also explains nested selectors within @scope emilio: @scope { foo ... } that's same as @scope { :where(:scope) foo ... } right? 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 emilio: Make it match the scope root <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. miriam: that would be different from other places where we represent the enclosing selector kizu: & is designed to represent the selector of the scoping root, not the scoping root kizu: Right now they could consider both the specificity of the scoping root *and* ??? kizu: So maybe we adjust to make it represent the scoping root miriam: So proposal is to make & represent :where(:scope) kizu: Yes. But we will need to see if it will not break something. emilio: It's behavior change either way miriam: I'm ok with this change kizu: I think it would be better romain: I'm unsure if removing specificity here is the right call romain: I think authors will expect the specificity, and it will be weird to remove it romain: Adding selectors makes things more specific. Not adding specificity when using & feels weird to me. miriam: Even though scope root selector adds no specificity by default? romain: but :scope has specificity, it's only wrapping in an at-rule that doesn't have specificity miriam: Are you saying have it be the same as :scope? romain: Maybe. romain: Writing a selector and having it produce zero specificity feels weird to me. romain: I don't think there's any other selector that behaves like that astearns: I'm also a little concerned about difference of & in @scope vs nesting astearns: but also, is there a way to get the specificity of the @scope prelude, if we make this change? miriam: No matthieud: No, and I think that was the reason for this. It allows authors to opt into this specificity 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. astearns: Do we believe authors will no longer need that option? 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 fantasai: if we were clearer about what specificity different things have it'd be less confusing fantasai: I think the problem is that it is so implicit miriam: It's implicit, but it's also following existing rules. miriam: The implicit one is the only new one <kizu> This is what we have right now: <kizu> - `@scope (article) { h1 {} }` — 0.0.1 <kizu> - `@scope (article) { & h1 {} }`— 0.0.2 <kizu> - `@scope (article) { :scope h1 {} }` — 0.1.1 <astearns> :scope-selector astearns: if we make this change, and then we do find that people need access to the prelude selector's specificity, what are our options? astearns: do we need a new pseudo, that targets the scope selector? kizu: Also some proposal to have a scope-end selector, so adding scope-start wouldn't be unreasonable 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 emilio: it differs from nesting in a really subtle way emilio: can do anything, but feels odd to me ... I understand why we don't want @scope { } to increase specificity emilio: adding specificity of :scope, that would be a problem emilio: but it's not great! emilio: I'm ok even with no change, but it's very weird behavior emilio: explaining it to people is going to be very "fun" miriam: Other part miriam: Does & match things other than scope root? fantasai: I think there's 3 ways that could go fantasai: we could say & matches things other than the scope root anywhere fantasai: that it only matches the scope root fantasai: or it matches things that match the scope root but only inside the scope fantasai: If you do `foo bar` inside `@scope` can foo match inside the scope? <kizu> Related post: https://blog.kizu.dev/scope-selector-nuance/ :) miriam: no because of the implicit scope selector, so only if you add `&` or `:scope` somewhere emilio: That implicit nesting means that .. <emilio> `@scope (..) { foo bar { ... } }` is basically `:where(:scope) foo bar { ... }` <fantasai> :where(:scope) foo bar, foo:where(:scope) bar, foo :where(:scope) bar ? miriam: No, it has the implicit `:where(:scope)` at the front miriam: unless you put the & somewhere else, so same as scope fantasai: So & represents the scope-start selector + :where(:scope) ? kizu: that's the question emilio: no, only scope-start <kizu> `&:hover :scope` fantasai: what miriam said is that if it doesn't represent `:scope` it can expand the scope miriam: it can match outside of the scope emilio: because `&` prevents the implicit `:where(:scope)` from getting inserted astearns: Should we go back to Miriam's idea of choosing what & matches, before we decide on specificity? astearns: I kinda like the idea that it can only match the scope root. astearns: idea of matching other things inside the scope root seems weird to me emilio: I think it's fine, but pretty tied to the specificity question emilio: would be nice not to define it as something magic emilio: we've explained it as :is(...) emilio: be nice to say it's just :where(:scope) or :scope, or ... emilio: Another option would be & doesn't avoid injecting that implicit scope selector, that might be weird in other ways emilio: and doesn't quite mean that it only matches scope root, just means selector can't escape the scope root emilio: which btw, is there a way of explicitly escaping the scope root? emilio: other than :where(:scope, :not(:scope))/ (or so) <romain> <div class="row"> <romain> ... <romain> <div class="row"> <romain> @scope (.row) { <romain> & :scope { ... } <romain> } <romain> Is this the question at hand? <romain> That & is ".row" and therefor this selector can match? <matthieud> (The subject can never escape the scope though, whatever the selector of the scoped rule be) astearns: What should we do? miriam: maybe write out all the options and take it back to the issue? astearns: Questions we have are 1. What exactly does the & represent. Seems like we have 4 options. astearns: and then 2. What specificity is added when you use an & astearns: Do we have just 2 options here? miriam: Emilio wanted it to match answer to first question astearns: Depending on answer to first question, specificity of & inside @scope may or may not match how it works in nesting miriam: since defining as specificity of parent selector, there's at least a match there emilio: Third question, should an & keep preventing the inclusion of the implicit :scope at the start of the selector astearns: which also may be informed by what we have it represent emilio: Right. if we choose that it is :scope or :where(:scope) matthieud: Different behavior for nesting and @scope emilio: I think my preference would be to define the parent selector as :where(scope) emilio: i.e. make & as :where(:scope) emilio: then it's like nesting, you always unconditionally add it unless it's already existing somewhere else emilio: It does lose the scope-start specificity, but I think that's OK emilio: because that's the behavior you get without & <kizu> +1 to make it :where(:scope) miriam: [missed] emilio: I think that would be the more consistent solution emilio: to say that & is :where(:scope) astearns: My concern with merely doing that is that this issue... nothing gets done astearns: We could resolve that & matches :where(:scope) and then allow the "being wrong on the internet" effect to elicit responses? miriam: I think it already worked to list out the options, and here we are back to take a resolution astearns: Anyone with concerns wrt & behaving as :where(:scope)? astearns: Like more time to work through examples etc.? andruud: It remains to be seen whether we can actually do it, since @scope has shipped emilio: Not yet shipping in FF fantasai: I think my suggestion would be to take a tentative resolution to give a chance to people not here <ydaniv> sounds good fantasai: or on vacation fantasai: gives a bit more time to people not here <emilio> +1 <kizu> +1 astearns: Ok, let's take a resolution and say that we will revisit in a week to confirm PROPOSED: & in @scope behaves as :where(:scope). We will revisit this in 1 week's time. fantasai: Can Miriam or someone else post a blog post or something, to see if anyone has comments? fantasai: can be short, like 3 paragraphs + point to issue [miriam and roman are maybe going to try]
Received on Wednesday, 2 July 2025 23:33:47 UTC