Exploration

Archive: 7 March 2012

There’s a subtle aspect of CSS descendant selectors that most people won’t have noticed because it rarely comes up: selectors have no notion of element proximity. Here’s the classic demonstration of this principle:

body h1 {color: red;}
html h1 {color: green;}

Given those styles, all h1 elements will be green, not red. That’s because the selectors have equal specificity, so the last one wins. The fact that the body element is “closer to” the h1 than the html element in the document tree is irrelevant. CSS has no mechanism for measuring proximity within the tree, and if I had to place a bet on the topic I’d bet that it never will.

Given these styles, the paragraph will not be boldfaced. That’s because both rules match, so the last one wins. The paragraph will be normal-weight.

“AHA!” you cry. “But the first rule has a higher specificity, so it wins regardless of the order they’re written in!” You’d think so, wouldn’t you? But it turns out that the negation pseudo-class isn’t counted as a pseudo-class. It, like the univseral selector, doesn’t contribute to specificity at all:

Selectors inside the negation pseudo-class are counted like any other, but the negation itself does not count as a pseudo-class.

If you swapped the order of the rules, you’d get a boldfaced paragraph thanks to the “all-other-things-being-equal-the-last-rule-wins” step in the cascade. However, that wouldn’t keep you from getting a red-on-red paragraph in this case: