W3C home > Mailing lists > Public > www-style@w3.org > January 2010

Re: [css3-selectors] Grouping

From: Tab Atkins Jr. <jackalmage@gmail.com>
Date: Sat, 9 Jan 2010 18:39:22 -0600
Message-ID: <dd0fbad1001091639i22f6b167y485fd00d9229aeb6@mail.gmail.com>
To: news <news@terrainformatica.com>
Cc: Boris Zbarsky <bzbarsky@mit.edu>, Nikita Popov <privat@ni-po.com>, www-style list <www-style@w3.org>
On Fri, Jan 8, 2010 at 11:38 PM, Andrew Fedoniouk
<news@terrainformatica.com> wrote:
> Tab Atkins Jr. wrote:
> Consider that you have DOM of 1000 elements and these two style rules:
>
> .foo { color: red; }
> .bar { color: blue; }
>
> style resolution procedure for the DOM will scan all 1000 elements
> and check if any of them have foo or bar class. So in total this
> would be 2000 comparisons. Most of them are usually misses (negative test
> result) but still.
>
> Now imagine that you have these two rules enclosed into the set:
>
> @set FooSet
> {
>  .foo { color: red; }
>  .bar { color: blue; }
> }
>
> This will exclude .foo and .bar rules from style resolution procedure.
> Effectively this is like you have no styles defined at all.
>
> Now let's imagine that we have some container in the DOM with id =
> #publications. Say it contains 100 DOM elements (from total 1000).
>
> Let's add following rule for such a container:
>
> #publications
> {
>  style-set: FooSet;
> }
>
> and run the same style assigning procedure:
>
> 900 elements will be skipped - no ordinary rules at all.
> 100 elements will have style-set defined and only for these
> elements these two selectors will be checked ( .foo and .bar)
>
> So you will have:
>
>  1) 200 checks of selectors (instead of 2000)
>
>  2) For compound selectors checks will be made for the depth of
>     subtree (from #publications element here) - not full tree.
>     This reduces needed CPU cycles too.
>
> Let me know if idea is clear enough.

It's clear, I'm just pretty sure it's unnecessary.  Rules starting
with an #id are pretty common, and a browser could easily match those
in precisely the method you describe if they wanted to.  You don't
need special syntax here, because you can reliably detect the most
common such areas that can use this optimization.

However, it appears that this simply isn't that great.  I can't find
the article talking about it right now, but when John Resig turned
jQuery's selector engine into Sizzle, he switched from
forward-matching to reverse-matching, like browsers do.  He found that
it was simply faster, even for cases like the ones you highlight
above, "#id foo", that would *seem* to be best done by looking up #id
and then searching its descendants.  He doesn't even have the same
strange circumstance of a partially-built DOM that browsers do - when
jQuery runs typically the entire DOM is present.

Backwards-matching is simply faster in nearly all cases.

> #publications.special :matches( :has-child(input),
>             :has-child(select), :has-child(textarea))
>
> you will get perfect combinatorial explosion.

Indeed, :has() is very inefficient.  That has nothing to do with
:matches, though.  It's exactly as inefficient if you expand it out to
three rules:

#publication.special :has(input),
#publication.special :has(select),
#publication.special :has(textarea) {}

:matches just makes it simpler to write.

(It's also possible that you *could* gain some efficiency by using
:matches here - "#publication.special
:has(:matches(input,select,textarea))" might be more efficient, since
it can do just a single tree-scan.)

~TJ
Received on Sunday, 10 January 2010 00:39:49 GMT

This archive was generated by hypermail 2.3.1 : Tuesday, 26 March 2013 17:20:23 GMT