You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[selectors] The forgiving nature of :has breaks jQuery when used with a complex :has selector #7676
jQuery has supported the :has pseudo-class for ages. However, its support is more powerful; in particular, it allows for jQuery extensions like :contains to appear within :has.
The way the jQuery selector engine works (and have worked for a long time), the selector is tried against querySelectorAll with minor modifications and if it throws, it goes through the internal selector engine. It's either-or.
Since selectors like ul:has(li:contains('Item')) no longer throw in Chrome, jQuery defers to querySelectorAll and such a selector returns 0 results even if the jQuery path should match something.
We can of course try to patch it in jQuery, perhaps defaulting selectors containing :has to use the jQuery selector engine. But it won't help countless apps using older jQuery versions. So I wanted to bring it for consideration for the standards committee. I understand if the decision is going to be "no changes in the spec are planned" but it'd be good to have this discussion and the decision made knowing the consequences.
As you can see, it didn't take long after the Chrome 105 release for us to get a bug report about this breakage: jquery/jquery#5098
Implementing :has according to the spec makes the browser break the jQuery test suite right now.
Even if we make the :has() unforgiving, it seems that there can be still same issues in :has(:is(.a:has(.b), .c)) since :is() is forgiving. (It seems that @lilles already asked about this here : jquery/jquery#5098 (comment))
The way the jQuery selector engine works (and have worked for a long time), the selector is tried against querySelectorAll with minor modifications and if it fails, it goes through the internal selector engine. It's either-or.
Shouldn't jQuery check CSS.supports("selector(:has(....))"), which should be unforgiving per spec? See #7280
Shouldn't jQuery check CSS.supports("selector(:has(....))"), which should be unforgiving per spec? See #7280
I agree that this is the correct way to validate :has() usage, but it's sad that even if JQuery applies this to the new version, there may be unexpected regressions when someone uses an older JQuery version. :(
Now I'm trying to merge a fix to Chrome to avoid existing JQuery conflict by following the WebKit's behavior. But I think that we need a way to handle this situation properly.
The one way I can imagine is to rename the pseudo class name in the spec so that there will not be any conflict with existing JQuery implementation (:has() -> :some-other-good-name())
If there's no real-world breakage, it might be worth just getting jQuery fixed by using CSS.supports(), rather than introduce a weird quirk in how :has() works vs. other modern selectors...
Reacted by Jonathan Neal, WebMechanic and Cetin Sert
Shouldn't jQuery check CSS.supports("selector(:has(....))"), which should be unforgiving per spec? See #7280
In Chrome 105, CSS.supports('selector(:has(div:contains(div)))') returns true. I'd gladly use this in jQuery if this was working as advertised.
Also, is this a "recent version of jQuery" kinda thing? Or would this change cause issues on older jQuery versions?
As I wrote in #7676 (comment), this affects virtually all jQuery versions used in the wild.
Is there any real-world site broken by the change? How frequent do we expect it to be to use jQuery-specific selectors inside :has() to begin with?
I am unable to answer this question. But it did both break our test suite and get us a report from a user at jquery/jquery#5098. @Rinzwind did you encounter this issue just in manual testing or did it actually break anything for you on a live site?
Now I'm trying to merge a fix to Chrome to avoid existing JQuery conflict by following the WebKit's behavior. But I think that we need a way to handle this situation properly.
Note that the WebKit behavior still breaks some jQuery selectors. True, it doesn't break:
div:has(span:contains('Item'))
but it still breaks:
div:has(div, span:contains('Item'))
Maybe that latter kind of selectors is not used as often in the wild.
Activity
mgol commentedon Sep 2, 2022
It's worth noting this affects all jQuery versions from 1.3 released in January, 2009 to the current 3.6.1 released a few days ago.
lilles commentedon Sep 2, 2022
This did not break with Safari shipping, because WebKit did not implement using forgiving selector list per spec: https://bugs.webkit.org/show_bug.cgi?id=244708
lilles commentedon Sep 2, 2022
@byung-woo @anttijk @emilio
byung-woo commentedon Sep 2, 2022
Even if we make the
:has()unforgiving, it seems that there can be still same issues in:has(:is(.a:has(.b), .c))since:is()is forgiving. (It seems that @lilles already asked about this here : jquery/jquery#5098 (comment))anttijk commentedon Sep 2, 2022
The current WebKit behavior (not by design) is to use forgiving parsing but fail the selector if the selector list ends up empty. That is
:has(:foo, bar) { }is valid and parses to
:has(bar) { }but
:has(:foo)is invalid.Perhaps this is actually the best option considering the jQuery issue.
emilio commentedon Sep 2, 2022
Shouldn't jQuery check
CSS.supports("selector(:has(....))"), which should be unforgiving per spec? See #7280byung-woo commentedon Sep 2, 2022
I agree that this is the correct way to validate
:has()usage, but it's sad that even if JQuery applies this to the new version, there may be unexpected regressions when someone uses an older JQuery version. :(Now I'm trying to merge a fix to Chrome to avoid existing JQuery conflict by following the WebKit's behavior. But I think that we need a way to handle this situation properly.
The one way I can imagine is to rename the pseudo class name in the spec so that there will not be any conflict with existing JQuery implementation (
:has()->:some-other-good-name())emilio commentedon Sep 2, 2022
Is there any real-world site broken by the change? How frequent do we expect it to be to use jQuery-specific selectors inside
:has()to begin with?emilio commentedon Sep 2, 2022
Also, is this a "recent version of jQuery" kinda thing? Or would this change cause issues on older jQuery versions?
emilio commentedon Sep 2, 2022
If there's no real-world breakage, it might be worth just getting jQuery fixed by using
CSS.supports(), rather than introduce a weird quirk in how:has()works vs. other modern selectors...mgol commentedon Sep 2, 2022
@emilio
In Chrome 105,
CSS.supports('selector(:has(div:contains(div)))')returnstrue. I'd gladly use this in jQuery if this was working as advertised.As I wrote in #7676 (comment), this affects virtually all jQuery versions used in the wild.
I am unable to answer this question. But it did both break our test suite and get us a report from a user at jquery/jquery#5098. @Rinzwind did you encounter this issue just in manual testing or did it actually break anything for you on a live site?
mgol commentedon Sep 2, 2022
@byung-woo
Note that the WebKit behavior still breaks some jQuery selectors. True, it doesn't break:
but it still breaks:
Maybe that latter kind of selectors is not used as often in the wild.
Make :has() invalid when all arguments are dropped.
lilles commentedon Sep 2, 2022
Opened issue for CSS.supports()/@supports: https://bugs.chromium.org/p/chromium/issues/detail?id=1359396
77 remaining items
mgol commentedon Feb 8, 2023
I have some doubts about the generic recommendation of wrapping with
:is()or:where()to get forgiveness; I submitted an issue about this: #8430.Selector: Stop relying on CSS.supports( "selector(...)" )
Selector: Stop relying on CSS.supports( "selector(...)" )
Selector: Stop relying on CSS.supports( "selector(...)" )
Selector: Stop relying on CSS.supports( "selector(...)" )
Selector: Stop relying on CSS.supports( "selector(...)" )
Selector: Stop relying on CSS.supports( "selector(...)" )
Selector: Stop relying on CSS.supports( "selector(...)" )
Selector: Stop relying on CSS.supports( "selector(...)" )
Selector: Stop relying on CSS.supports( "selector(...)" )
Selector: Stop relying on CSS.supports( "selector(...)" )
Bug 1804852 [wpt PR 37423] - Make :has() unforgiving, a=testonly
css: :has() takes a non-forgiving relative selector list too
css: parse the :nth-child of-list and :has() non-forgivingly, reject …
css: parse the :nth-child of-list and :has() non-forgivingly, reject …