My talk on CSS runtime performance
nolanlawson.com
nolanlawson.com
.cls[attr="value"] is always slower than [attr="value"].cls
But I never see anybody using the second one.
I think it's also interesting that there is no way to do figcaption.cls inverted like .clsfigcaption.
It's strange that default CSS that comes with tools like Wordpress abuses pseudo-selectors as much. I think everyone just writes it off as "it's the CSS 3 way."
On interesting example is that some javascript libraries to highlight code syntax will use ancestor selectors like .highlighted .keyword, which in my mind is crazy. You are making the classes through javascript, you could just use a single glass, which is what Highlight.js does: its classes look like .hlts-kw.
One time I had to deal with layout in CSS being too slow. It was not because of webpage, but an electron app for android that needed to get the bounding rectangle a lot to place divs for its custom GUI elements on screen. Since changing the DOM/CSS changes the bounding rects, placing a div and then checking the bounding rect again was a performance cost. The solution ended up being caching the client rect once before updating the DOM to avoid the thrashing.
Anyway, great talk :D I hope more people become aware CSS isn't magic, nor a black box, so they can think twice before writing their selectors. Sometimes I see CSS code with superfluous nested ancestors (e.g. .wrapper .content .post-body img), and I think that happens because it really just works, but unfortunately it seems that mentally carries on after a developer stops being a beginner, because the CSS just keeps working anyway.
I understood the right to left was on the element level and not on the node level so I would think attr="value wouldn't have an effect.
You're right in that there's less information out there for CSS engines (from flipping through slides on this talk, it looks like a great way to improve on that situation!), but there's just a lot more to _say_ about SQL performance. And a lot of what's being said about the latter is honestly pretty sketchy :-)
Hey, have you instrumented this by chance? I assumed browsers have pretty smart query optimizers by now.
The reason why the right-to-left rule makes sense _between compounds in a complex selector_ (i.e., “the parts that are separated by a space”, for an imprecise term) is that this is the part that applies to the element you are computing style for right now. I.e., say that you have a rule like
.a.b span { color: whatever; }
This rule will apply to a <span> (the span is the “subject” of the rule) that has an .a.b element somewhere up higher in the tree. If you have made the rule specific enough that it rejects on the subject (say, you're computing style right now for a <h1>, not a <span>), you can skip the entire rule right away. (Most rules do, after all, not match most elements, so rejection is what you want to optimize for.) But once that “span” selector matches on some element, you need to walk the ancestor chain from that element, potentially every single ancestor, to verify that there's no parent that has both classes .a and .b, before you can reject the rule. So rejecting on the subject (save for :has(), which is a story in its own) needs to look at one element, rejecting on something non-subject is much worse. (The Bloom filter would stop early if you don't have at least something with .a and something with .b in your tree, a so-called “fast reject”, but it can't distinguish <div class="a"><div class="b"><span> from <div class="a b"><span>.)The best thing for selector performance _by far_ is to write the subject so that most elements don't even see it, by means of getting it into the right hash table bucket. A selector like “#xyz” is going to be _so_ much faster than “#xyz *”. But of course, most sites are not really style bound; CSS performance is something you should probably look at after you have your HTTP and JavaScript issues under control.
(I work on Chromium style performance)
Edit: to illustrate my point better, it used to be that if you wanted to make a table with alternating row colors you just used a class on each row. Then :nth-child(odd) and :nth-child(even) came out and everyone was like "just use that instead! No more classes in every row!" And now we have .foo-table :nth-child(odd) > td because obviously there's a tbody/thead/tfoot between tr and table and nobody knows if you should do this or .foo-table > :is(thead, tfoot, tbody) > :nth-child(odd) > td or which one is faster or if you should just use .odd > td because HTML TABLES ARE THE REAL EVIL TABLES IN WEB HISTORY. CSS TABLES WERE SAINTS COMPARED TO THIS. Anyway, every browser has different optimizations, and I have 5 different ways to make a row color alternate. This is the problem. When we have actual complex styling that makes use of the most powerful CSS selectors, all common optimization for simple stuff fall apart. So why even use powerful CSS selectors when they have potential to be permanently slow on HTML code that you may not ever be able to change in the future?
I'm honestly just professing ignorance! Along with generally wondering about the state of CSS query optimizers, I think the two have the same specificity, which (in my very-incomplete mental model) makes me think that they're about the same amount of work to resolve.
If Nolan stops by maybe he can weigh in. :^)