When rules collide
The single most common CSS frustration — "my rule is right there and the browser is ignoring it" — is never random. A fixed algorithm, the cascade, decides every conflict, and once you know it you can predict the winner instead of guessing.
In the lesson 4-1 sandbox, two rules targeted the same paragraph:
p { color: gray; }
.warning { color: red; }<p class="warning">Careful!</p>
The text came out red. The cascade decides every such conflict, checking in order:
- Importance: declarations marked
!importantbeat everything. Use it almost never, because it makes CSS unfixable. - Specificity: more specific selectors beat less specific ones.
.warningis more specific thanp, so red wins. - Source order: still tied? The rule written last wins.
Separately, some properties (like color and font-family) inherit from parent to child when nothing targets the child directly. That is why setting fonts on body in lesson 4-2 styled the whole page.
The specificity score
Count a selector's parts into three buckets, and compare bucket by bucket:
| bucket | counts | example |
|---|---|---|
| IDs | each #id | #site-title → (1,0,0) |
| classes | each .class | .card .warning → (0,2,0) |
| types | each tag name | nav a → (0,0,2) |
Compare left to right like version numbers: (1,0,0) beats (0,9,9), because one ID outranks any number of classes. Inline styles (a style="..." attribute in the HTML) sit above all selectors.
Practical advice that will save you hours: style with classes almost everywhere. Flat class selectors keep every score at (0,1,0), so the winner is simply whichever rule comes last in the file. The cascade becomes boring, and boring is what you want.
Quiz
The page has <p id="intro" class="lead">. Both #intro { color: green; } and .lead { color: purple; } exist, with .lead written last. What color is the text?
Code exercise · javascript
Run this specificity calculator. It splits a selector on spaces and counts IDs, classes, and types into the three-bucket score from the table above.
Code exercise · javascript
Your turn: write wins(a, b) that returns whichever selector has higher specificity, comparing ids first, then classes, then types. On a complete tie return b, because the later rule wins by source order.