- 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