Skip to content

[selectors] Backwards combinators #12453

@LeaVerou

Description

@LeaVerou

Combinators that could go "backwards" have been proposed before, but until :has() they were rejected on the basis of feasibility. However, now that we have :has(), they are merely syntactic sugar:

  • Parent: E < F as sugar over F:has(> E)
  • Previous adjacent sibling: E - F as sugar over F:has(+ E).
  • Previous sibling: E -~ F as sugar over F:has(~ E)
  • Ancestor: E << F as sugar over F:has(E)

If we use -, space between that and the preceding selector is mandatory for disambiguation, for the same reason it is in calc(). Other ideas to avoid this wart:

  • Duplicated versions of the existing combinators (++ instead of -, ~~ instead of -~)
  • < prefix: <+ for previous adjacent sibling, <~ for previous sibling. I think this may be my favorite, as with it all backwards combinators start with <, which gives them a nice predictability.

Pros & Cons

Why add them?

  • Improved DX for authors. Inverting existing combinators is much more natural than using a completely different syntax to go in the opposite direction. Sure, the mechanics of going in the opposite direction are vastly different, but to authors that’s an implementation detail.
  • Can be used by UAs for performance optimizations. For example, to make relative references in IDREF attributes feasible. Currently, the previous sibling can only be specified as :has(+ &), which seems extremely inefficient.
  • As they are more limited, they could be granularly allowed in contexts where :has() is not (such restrictions have been discussed in the past for various features)

Why not add them?

  • It could be argued that the simplicity is actually a con, because it hides the performance characteristics. However, I'd argue that a) most authors are not intimately familiar with the perf characteristics of selectors anyway and b) at least for bounded combinators like parent and previous sibling, simply having them could make them more performant than the :has() version.

cc @tabatkins @fantasai

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions