views:

127

answers:

3

Is there a precedence to combinators like

a > b ~ c d

(Note the space between c and d is the descendant combinator)

Or is it just read left-to-right, like

((a > b) ~ c) d

?

+2  A: 

It doesn't matter.

a > b c 

will match the same elements regardless of whether you do it

(a > b) c

or

a > (b c)

I think that browsers go right-to-left.

Šime Vidas
A: 

the spec doesn't mention anything about precedence (that I can find) but I believe it's strictly left -to- right evaluation

Scott Evernden
Yeah, I didn't find anything in the spec either, which is why I asked :)
Mark
+3  A: 

According to Google, they're evaluated from right to left:

The engine [Gecko] evaluates each rule from right to left, starting from the rightmost selector (called the "key") and moving through each selector until it finds a match or discards the rule.

Mozilla's article, Writing Efficient CSS for use in the Mozilla UI has a section that describes how their CSS engine evaluates selectors. This is XUL-specific, but the same layout engine is used both for Firefox's UI and pages that display in Firefox's viewport.

As described by Google in the above quote, the key selector simply refers to the right-most item, so again it's from right to left:

The style system matches rules by starting with the key selector, then moving to the left (looking for any ancestors in the rule’s selector). As long as the selector’s subtree continues to check out, the style system continues moving to the left until it either matches the rule, or abandons because of a mismatch.


In fact, if you were to ask me to read selectors and describe what they select in plain English, I would read them from right to left too (not that I'm certain whether this is relevant to implementation details though!).

So, the selector:

a > b ~ c d

would mean

Find all d elements
that are descendants of c elements
that are siblings of, and come after, b elements
that are direct descendants of a elements

BoltClock
Yea. Right-to-left because the last simple selector (d) is the one of which the result is a subset of. The other simple selectors (a, b, and c) are present just to narrow down the result.
Šime Vidas
But say I have two divs `#A` and `#B`, and `#A` has 100 spans inside, `#B` just one. Then evaluating `div#A span` from left to right would be much easier and probably faster then getting all spans first, or not?
poke
@poke: I agree it would be faster, but it appears that's not how it's evaluated by engines as we know them. At least it's faster than, say, checking every span to see if it's a descendant of every div...
BoltClock
If I remember correctly from a lecture on Youtube I once watched, ID selectors get special treatment. If the selector string contains ID selector(s), then there may be a divergence from the right-to-left rule. Also, browsers have references to all elements with ID's (so that they don't have to search for them for every selector they encounter).
Šime Vidas
@Šime: Ah, that's very interesting. +1
BoltClock
Here, this video is related to this issue: http://www.youtube.com/watch?v=a2_6bGNZ7bA
Šime Vidas
Arghhh! I tried parsing right-to-left something like `body > span > a` but what I ended up doing was finding all `a` s and then filtering them to those that had a `span` parent, and then filtering those (the filtered `a` s) to the ones that had a `body` parent... doesn't exactly work :p Shouldn't this be left-to-right? You can safely drop off the `body` after you've filtered the `span` s, but you can't do it the other way around.
Mark
@Mark: I wonder if adding an illustration to my answer of how *I* parse it would help any :S
BoltClock
@BoltClock: Naw, it's okay. I figured it out. Silly me :) Recursion was the answer.
Mark