Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[selectors] Wrapping with :is() to get forgiveness changes semantics #8430

Open
mgol opened this issue Feb 8, 2023 · 4 comments
Open

[selectors] Wrapping with :is() to get forgiveness changes semantics #8430

mgol opened this issue Feb 8, 2023 · 4 comments
Labels
selectors-4 Current Work

Comments

@mgol
Copy link

mgol commented Feb 8, 2023

The discussion in #7676 ended with a conclusion to make :has() unforgiving since you can always wrap its contents with :is() or :where():

fantasai: i support restricting to :is and :where, it's really simple, and because we do it this way you can control whether something is forgiving or not by wrapping in :is or :where

This has been since incorporated into the spec at https://w3c.github.io/csswg-drafts/selectors/#typedef-forgiving-selector-list:

Note: Style rules still use the normal, unforgiving selector list behavior. is used in :is() and :where() only. Although it does have some minor implications on specificity, wrapping a style rule’s selector in :is() effectively "upgrades" it to become forgiving, so long as it doesn’t contain any pseudo-elements (which aren’t valid in :is() or :where()).

However, this doesn't look so simple to me, since :is/:where take global selectors. For example, someone wanting to run:

document.querySelectorAll('#test-elem:has(:new-pseudo-with-limited-support,div span)')

in a forgiving manner so that it works in browsers without support for :new-pseudo-with-limited-support may be surprised that the following:

document.querySelectorAll('#test-elem:has(:is(:new-pseudo-with-limited-support,div span))')

will no longer require both the span and its ancestor div to be descendants of #test-elem.

Do I not understand something about this recommendation or is it not precise enough?

@Loirooriol
Copy link
Contributor

You can use

document.querySelectorAll('#test-elem:has(:is(:new-pseudo-with-limited-support),div span)')

@mgol
Copy link
Author

mgol commented Feb 8, 2023

@Loirooriol yes but then you need to precisely identify which parts you consider problematic; this can be hard e.g. if what you pass to :has() is dynamic. In any case, the wording:

wrapping a style rule’s selector in :is() effectively "upgrades" it to become forgiving

suggests wrapping the whole selector part you're interested it, at least that's how I read it.

@Loirooriol
Copy link
Contributor

You can also split :has() into multiple, so that each one gets a complex selector, and wrap them all inside a single :is().

document.querySelectorAll('#test-elem:is(:has(:new-pseudo-with-limited-support), :has(div span))');

But yeah, may be good to warn about this. Also in nesting when omitting &, .foo .bar a.k.a. & .foo .bar and :is(.foo .bar) a.k.a. & :is(.foo .bar) are different.

@tabatkins
Copy link
Member

Yeah, :is() is a no-op (ignoring specificity) if you wrap an entire selector in it, or you wrap just a compound selector in it. If you have a combinator inside the :is() and outside it, it does indeed change the behavior.

And since :has()'s argument is a relative selector, it always has a (perhaps implicit) combinator at the start, which you can't include in the :is(), so wrapping the entire :has() argument will always run afoul of this issue. You have to instead push it down to just wrap compound selectors, or lift it entirely outside as :is(:has(...)).

(Lifting it outside doesn't act quite the same - it'll prevent an invalid selector in :has() from invalidating the whole selector, but it won't let you drop just the invalid selector from the :has() argument and continue with the rest. But generally that should be fine.)

@fantasai fantasai added the selectors-4 Current Work label Jun 1, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
selectors-4 Current Work
Projects
None yet
Development

No branches or pull requests

4 participants