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

[css-selectors] :has() and performance #3345

Closed
ExE-Boss opened this issue Nov 26, 2018 · 7 comments
Closed

[css-selectors] :has() and performance #3345

ExE-Boss opened this issue Nov 26, 2018 · 7 comments

Comments

@ExE-Boss
Copy link
Contributor

https://drafts.csswg.org/selectors-4/#profiles

The CSS selectors specification claims that :has() can’t be optimised, which isn’t accurate, as when :has() is the last component of a selector (with no nested :has() pseudo-classes), then:

a b c {}

and

a b:has(c) {}

would be essentially identical in terms of performance, and therefore viable for the live profile.

@bkardell
Copy link
Contributor

I'm not an implementer so I don't know how valuable my comments on this should be considered, but I don't think that it is evaluation of the selector that is particularly hard, but rather the fact that it changes the subject and what tests need to be run on which things and when are different and don't fit neatly into existing strategies for avoiding a ton of extra work. That said, I do think there are probably limitations in what you could write and new optimizations that could strike a doable balance.

@emilio
Copy link
Collaborator

emilio commented Nov 26, 2018

would be essentially identical in terms of performance, and therefore viable for the live profile.

That is not true. b.matches('a b:has(c)') requires looking at every descendant of b, while c.matches('a b c') does not. Evaluating the selector is much more expensive.

@emilio
Copy link
Collaborator

emilio commented Nov 26, 2018

What @bkardell points out is also a problem, too, since that means that changes to an element can now affect the styles of arbitrary ancestors, and computing which ancestors are affected is not quite trivial.

@emilio
Copy link
Collaborator

emilio commented Nov 26, 2018

Even with that I don't think it'd be acceptable perf-wise. Parallelism only gives you a linear speedup with the number of cores best-case, while evaluating :has is exponential.

@ExE-Boss
Copy link
Contributor Author

ExE-Boss commented Nov 26, 2018

(previous comment which I removed because I didn’t feel like it added anything valuable to the discussion)

Well, at least Stylo is massively parallel, which would certainly help with performance.


would be essentially identical in terms of performance, and therefore viable for the live profile.

That is not true. b.matches('a b:has(c)') requires looking at every descendant of b, while c.matches('a b c') does not. Evaluating the selector is much more expensive.

That’s from JavaScript.

I primarily meant the initial parsing, which ends up being fast‑ish since once you encounter c, you can send an event back to b, which would’ve been marked as potentially matching a :has(…) selector and be updated as such.

@emilio
Copy link
Collaborator

emilio commented Nov 26, 2018

That’s from JavaScript. I mean the initial parsing, which ends up being fast‑ish since once you encounter c, you can send an event back to b, which would be marked as potentially matching a :has(…) selector and be updated as such.

That's not true either. The way style engines work is per-element. You build a list of all the rules on the page that match a certain element, for which you effectively need to do the work element.matches does for each selector of the page. There are optimizations of course to avoid matching every selector against every element (so in your example we'd only match it against every b element that has an a ancestor, but those wouldn't handle :has.

@fantasai
Copy link
Collaborator

I'm going to point to this thread, where Boris Zbarsky has already answered this question in detail:
https://lists.w3.org/Archives/Public/www-style/2010Jan/thread.html#msg473
I'm going to suggest reading carefully through all his replies. And I'm going to close this issue, as the assertion in the OP (“would be essentially identical in terms of performance”) is invalid.

We would all love for this to be performantly solved, and I'm sure it's possible with some kind of sophisticated caching and/or crazy inversion of the existing matching engines, but until someone actually does it and the other implementers agree to also take it on as a priority, it can't go in the spec, which is supposed to reflect an agreement of what should be imminently implemented.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants