Skip to content

[selectors] May new pseudos using forgiving parsing be introduced in the future? #8378

Closed
@mgol

Description

In #7676, I reported the forgiving nature of :has() to be breaking jQuery. tl;dr is jQuery uses try-catch on some version of the selector passed to qSA and does its own traversal when it throws as a fallback. With the help of some support tests, a regex is constructed that identifies buggy selectors which don't get passed through qSA at all and go straight to the jQuery traversal.

:has() has been since made non-forgiving but during the discussion it was suggested that jQuery shouldn't rely on try-catch as some selectors may be forgiving and the fact there's no error thrown doesn't mean the selector works natively. We were directed to use CSS.supports( "selector(...)" ) which was made always non-forgiving1, the spec change that only made it to Firefox stable so far. jQuery 3.6.2 implemented this change in browsers with spec-compliant CSS.supports( "selector(...)" ) (i.e., currently just Firefox). jQuery 3.6.3 changed that to CSS.supports( "selector(:is(...))" ) as bare selector(...) doesn't support selector lists which jQuery accepts as input.

However, we didn't take into account that those two approaches differ and qSA is way more forgiving than CSS.supports( "selector(...)" ), even beyond :is() & :where(). For example, native qSA( ":before" ) returns 0 results but does not throw while CSS.supports( "selector(:is(:before))" ) is false. The same for unterminated brackets: qSA( "[attr=val" ) works and returns valid results but both CSS.supports( "selector(:is([attr=val))" ) and CSS.supports( "selector([attr=val)" ) are false. We've already gotten multiple reports about these differences.

Due to the above issues, we're considering reverting to the previous behavior and relying on qSA in try-catch and just marking :has() as buggy in all browsers where it's still forgiving (i.e. now both Chrome & Safari but that should change soon). However, we'd feel safer hearing some assurances that we won't hit a similar issue with other pseudos that we've just gone through with :has(). The comment #7676 (comment) and the spec2 suggest the list is fixed and no future selectors will ever use forgiving parsing other than :is() or :where() but I wanted to double check. We'd only have problems if such a pseudo matched another one implemented by jQuery, i.e. roughly anything from Selectors Level 3 or any of the jQuery extensions like :contains() or :eq().

jQuery doesn't currently plan to implement :is() or :where() in its custom traversal; if it one day does, it will be a complete rewrite of the selector module so this discussion will likely be irrelevant.

Footnotes

  1. https://w3c.github.io/csswg-drafts/css-conditional-4/#dfn-support-selector

  2. https://drafts.csswg.org/selectors/#forgiving-selector

Metadata

Assignees

No one assigned

    Labels

    Closed as Question AnsweredUsed when the issue is more of a question than a problem, and it's been answered.selectors-4Current Work

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions