Introduction
Sooner or later you will write a perfectly correct rule, reload the page, and see nothing change. Another rule is winning. The "C" in CSS stands for cascading, the system that decides which rule wins. Once you understand it, a confusing part of web development becomes predictable.
How it works
When rules conflict. Several rules can set the same property on the same element. The browser works through these questions and stops at the first one that gives an answer:
- Importance and origin. Does one have
!important? Is one a browser default, and the other yours? - Specificity. Which selector is more specific?
- Source order. If they are still tied, the one that comes later wins.
Notice that specificity comes before order. A strong selector near the top of a file beats a weak selector at the bottom.
Counting specificity. Think of three columns, ids, classes and types, compared from left to right.
| Selector | Ids | Classes, attributes, pseudo-classes | Types |
|---|---|---|---|
p | 0 | 0 | 1 |
.note | 0 | 1 | 0 |
p.note | 0 | 1 | 1 |
nav a:hover | 0 | 1 | 2 |
#menu | 1 | 0 | 0 |
A single id beats any number of classes, because it wins the first column. The * selector and combinators score nothing. Inline style attributes beat all of these selectors.
Inheritance. Some properties pass down from parent to child automatically. Mostly these are about text: color, font-family, font-size, line-height. Set the font once on body and the whole page gets it. Box properties such as border, margin and padding do not inherit, because it would be absurd for every child to get its parent's border.
An inherited value is the weakest of all. Any rule that targets the element directly beats it, even *.
You can control inheritance with special values: inherit forces it, initial resets to the property's starting value, and unset picks whichever is natural for that property.
!important. Adding it after a value lifts that declaration above normal ones. It is tempting and usually a mistake, because the only way to beat it is another !important. It belongs in rare places, such as utility classes that must always apply, or accessibility overrides.
Lowering specificity on purpose. The :where() function has zero specificity, so :where(nav) a is easy to override. Its cousin :is() takes the specificity of its strongest argument.
Syntax
p { color: gray; } /* 0, 0, 1 */
.note { color: teal; } /* 0, 1, 0: wins */
Example
The first paragraph has no colour rule of its own, and the second one does. Compare what happens to each.
Line by line
.boxsets a colour on thediv. The first paragraph has no colour of its own, so it inherits crimson.- The second paragraph has a rule targeting it directly, and that beats any inherited value.
borderis set only on.box. The paragraphs do not inherit it, so there is one box and not three.
Expected result
A single bordered box. The first line is crimson and the second is teal.
In the real world
Large codebases suffer when specificity grows out of control, with each new rule having to be stronger than the last. This is why many teams keep selectors to a single class. Modern CSS also has @layer, which lets a team rank whole groups of styles, so that a framework's rules can never beat their own.
Common mistakes
- Assuming that later always wins. It only wins a tie.
- Reaching for
!importantbefore understanding why a rule loses. - Using ids for styling, making them hard to override.
- Expecting a border or margin to inherit.
Best practices
- Keep specificity low and even across your stylesheet.
- Set fonts and colours on
body, and let them inherit. - Use browser developer tools: they show which rules lost and why.
- Treat every
!importantas a question to investigate.
Summary
When rules conflict, the browser checks importance, then specificity, then order. Specificity is compared as ids, then classes, then types. Text properties usually inherit and box properties do not. Keeping selectors simple avoids most of these fights.
Quick check
Key takeaways
- When rules conflict, specificity is compared first, then source order.
- An id outranks any number of classes.
- Text properties usually inherit, and box properties usually do not.
- !important fixes one conflict and creates the next.
Practice problems for this lesson
My notes
Write down what you want to remember from this lesson. Notes are saved on this device as you type, and appear on your dashboard.