Re: [csswg-drafts] Mixing :is() (or equivalent) with pseudo-elements (#9702)

All right, Agenda+ to discuss this.

For clarity, the proposal here is that we slightly alter the Selectors data model, such that:

* *before* matching a `<complex-selector-unit>` (aka a compound selector + pseudo-elements, no combinators), we grow the set of currently-matched elements (which are about to be filtered by the compound) by adding all the pseudo-elements of all the currently-matched elements.
* *after* matching a compound selector, we filter out all the pseudo-elements that weren't matched explicitly by the `<complex-selector-unit>` (then apply the combinator and continue on, as normal)

This means that, for example, `:is(.foo, .foo::before, .foo::after):hover` will "work as expected":
1. We open, as usual, with the match set being the entire document.
2. We temporarily add all pseudo-elements of all elements to the match set.
3. We filter to only keep any elements/pseudo-elements that are hovered, and that are either `.foo`, `.foo::before`, or `.foo::after`.
4. We remove any remaining pseudo-elements that weren't explicitly matched (in this case, there's nothing to remove).
5. The end result is equivalent to `.foo:hover, .foo::before:hover, .foo::after:hover`.

However, a closely related selector, like `:is(*, ::before, ::after).foo:hover` will not match any pseudo-elements, because the `.foo` simple selector will filter out all the pseudo-elements.

For existing "normal" cases like `:hover`, we'll add all the pseudos, then remove all the pseudos (since none of them were mentioned in the complex-selector-unit), so there's no change in behavior.

For nesting, then, this will mean that the following will work:

```css
.foo {
  ...
  &, &::before, &::after {
    ...
    &:hover { ... } /* today, this is only equivalent to `.foo:hover`
  }
}
```

---------------

Some limitations to this approach:

1. As currently described, `.foo:is(*, ::before, ::after)` won't work. But this did work in the original `-webkit-matches()`. Is this limitation okay? If not, how can we adjust the model to allow that to work as well? Since simple selectors can be rearranged in a compound, this should presumably work identically to `:is(*, ::before, ::after).foo`, too. (If these two aren't identical, then this continues to be "not a simple selector" and needs more adjustments.)
2. As currently described, `:hover:is(::before)` and `:is(::before):hover` are identical - they're both equivalent to `::before:hover`. I think this is the more commonly intended ordering, but in cases where you want the other ordering, you can't express it with `:is()` or Nesting under this model. Is this limitation okay? (Assuming we have the pseudo-combinator, you could instead write `:hover :> :is(before, after)` or whatever, which would allow you to solve it when needed.)

-- 
GitHub Notification of comment by tabatkins
Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/9702#issuecomment-3250059981 using your GitHub account


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

Received on Wednesday, 3 September 2025 17:03:36 UTC