The cascade
Cascade and specificity
Predict which declaration wins by considering importance, origin, cascade layers, selector specificity, and source order.
Several rules can set the same property on the same element. Only one value can win. The cascade is the algorithm that picks it, and it’s the “C” in CSS.
Once you know this algorithm, “why is my style not applied?” becomes a checklist.
The order of checks
When two declarations compete, the browser compares them in this order. The first difference decides:
- Relevance. Does the selector match, and does its media query apply?
- Origin and importance. Browser defaults, user styles, author styles (yours), and animations each have a rank.
!importantflips it. - Cascade layers. Later
@layers beat earlier ones. - Specificity. How precise the selector is.
- Scope proximity, only with
@scope. - Source order. When everything ties, the last declaration wins.
Day to day you’re comparing your own normal styles, so steps 4 and 6 do most of the work.
Specificity
Specificity is a weight the browser calculates from the selector. Think of it as three counters:
- IDs count the most
- classes, attribute selectors, and pseudo-classes come next
- type selectors and pseudo-elements count the least
One ID beats any number of classes. One class beats any number of type selectors. Combinators and * add nothing.
p { color: black; }
.intro { color: navy; }
A paragraph with class="intro" is navy. Both are normal author styles in the same layer, so specificity decides, and a class outranks a type selector. Swap the two rules and it stays navy.
When specificity ties, the later declaration wins. That’s why the order of your stylesheets matters.
Layers
Cascade layers let you state the priority instead of relying on selectors:
@layer reset, components, utilities;
Now anything in utilities beats anything in components, whatever the selectors. Styles outside any layer beat all layered styles. Very useful for third-party CSS: put the library in an early layer and your own styles win without a fight.
Two tools to know about
!important moves a declaration to a higher rank. It’s not “more specificity”, it’s a different step of the algorithm, and it even reverses layer order. Use it for real exceptions, not to win an argument with your own CSS.
:where() does the opposite. Whatever selector you put inside it contributes zero specificity. Great for defaults you want to be easy to override.
My advice
Keep selectors low and flat. One class per component. If you find yourself adding selectors to beat other selectors, stop and simplify the structure instead. Specificity wars only go one way.
When a value looks wrong on the course page, find the crossed-out declaration in DevTools and read why it lost. Change one factor at a time, the selector, then the order, until you can predict the winner before you refresh.
Lesson completed