CSS combinator precedence?
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
?
No, there is no notion of precedence in combinators. However, there is a notion of order of elements in a complex selector.
Any complex selector can be read in any direction that makes sense to you, but this does not imply that combinators are distributive or commutative, as they indicate a relationship between two elements, e.g. ancestor descendant
and previous + next
. This is why the order of elements is what matters.
According to Google, however, browsers implement their selector engines such that they evaluate complex selectors 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. (dead link)
As described by Google in the above quote, the key selector simply refers to the right-most simple selector sequence, 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.
Bear in mind two things:
-
These are documented based on implementation details; at heart, a selector is a selector, and all it is intended to do is to match an element that satisfies a certain condition (laid out by the components of the selector). In which direction it is read is up to the implementation; as pointed out by another answer, the spec does not say anything about what order to evaluate a selector in or about combinator precedence.
-
Neither article implies that each simple selector is evaluated from left to right within its simple selector sequence (see this answer for why I believe this isn't the case). What the articles are saying is that a browser engine will evaluate the key selector sequence to figure out if its working DOM element matches it, then if it does, progress onto the next selector sequence by following the combinator and check for any elements that match that sequence, then rinse and repeat until either completion or failure.
With all that said, 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:
Select any
d
element
that is a descendant of ac
element
that is a sibling of, and comes after, ab
element
that is a child (direct descendant) of ana
element.
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.