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

> Even if we use `:is()` directly, this should still match all of `.foo:hover`, `.foo::before:hover`, `.foo::after::hover` without violating the selectors data model:

Unfortunately, it doesn't; reshuffling the syntax doesn't help us here, because the problem is much deeper in the Selectors data model.  When you have `:is(...)`, that is *implicitly equal* to `*:is(...)`. The `*` selector can only match elements that are currently visible in the tree, and that *does not* include pseudo-elements.

So, in `:is(.foo, .foo :> :pseudo(before), .foo :> :pseudo(after)):hover`, the subject of the `:is()` (the things matched against the `*`, or whatever else shared the compound with the `:is()`) are the `.foo`, `:pseudo(before)`, and `:pseudo(after)` parts, but those latter two can never match the `*` outside the `:is()`.

This is gonna be the problem for *anything* that works via a simple selector (like a pseudo-class) - the set of elements they are filtering is chosen before any of the filters are applied, and by default elements in "hidden" trees, like pseudo-elements, aren't going to be in that set.

That was the point behind my `=` combinator and the parenthesized syntax - the parenthesized syntax allows us to do something slightly different (because it's not part of a compound selector, there's nothing else limiting it to a particular set of matched elements), and the `A = B` combinator just says "elements that match A, and also match B".

-----------

Thinking on this a bit, I suppose another possibility would be to slightly change the Selectors data model, such that all the "hidden" elements *are* in the match set before each compound selector is applied, but they're *post-filtered* out of the match set if they weren't explicitly matched by something in the compound selector, before the next combinator is applied.

That is, `*` would select all elements *and pseudo-elements* on the page, but unless a `::foo` is in the `<complex-selector-unit>`, the pseudo-elements are removed from the final match result. That would allow `*:is(.foo, .foo::before)` to work (matching both `.foo` elements and their `::before` pseudos), while still preventing `.foo:is(*, ::before)` from working (it would only match `.foo` elements, as the `::before`s wouldn't match the `.foo` simple selector).

I wanna sit with this one a bit, but I think it might actually solve our problems generally, for both `:is()` and Nesting, without actually needing any new syntax at all?

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


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

Received on Tuesday, 2 September 2025 20:54:37 UTC