The idea
Sooner or later you'll write a CSS rule and nothing happens. Almost always, another rule is winning. The browser resolves conflicts with a fixed algorithm, the cascade, and once you know its three main steps, "why isn't my CSS working?" becomes a quick diagnosis instead of a guessing game.
Step 1: later rules win (when equally specific)
Start with the simplest conflict. Two rules both set the colour of the price, and they use exactly the same selector. Which colour does the price end up?
<style>
.price { color: green; }
.price { color: #7a4b2a; }
</style>
<p class="price">Rp 95.000</p>
Two rules with the same selector set color. The one that comes later in the stylesheet wins: brown. This also applies across files: a stylesheet linked later overrides an earlier one.
Step 2: more specific selectors win
Now the rules use different selectors that all match the same price. Order no longer decides it. Before reading the explanation, try to guess what colour each price will be:
<style>
#featured { color: purple; } /* 1 id */
.card .price { color: #7a4b2a; } /* 2 classes */
.price { color: green; } /* 1 class */
p { color: blue; } /* 1 type */
</style>
<article class="card" id="featured">
<p class="price">Rp 95.000</p>
</article>
<p class="price">Rp 120.000</p>
Specificity scores each selector by counting three things, compared left to right like version numbers:
| Selector | ids | classes, attributes, pseudo-classes | types, pseudo-elements | Score |
|---|---|---|---|---|
p | 0 | 0 | 1 | 0-0-1 |
.price | 0 | 1 | 0 | 0-1-0 |
.card .price | 0 | 2 | 0 | 0-2-0 |
nav a:hover | 0 | 1 | 2 | 0-1-2 |
#featured | 1 | 0 | 0 | 1-0-0 |
Higher score wins, regardless of order. One id beats any number of classes; one class beats any number of types. The first price is inside #featured, but #featured targets the article, not the paragraph, so the paragraph's own rules decide: .card .price (0-2-0) beats .price (0-1-0) → brown. The second price only matches .price and p → green.
Inline styles (style="..." on the element) beat any selector, which is one reason to avoid them.
Step 3: !important (and why to avoid it)
color: red !important; jumps to the front of the queue, above all normal declarations. It's tempting when a rule won't apply, but the only way to override it later is another !important, and stylesheets that go down that road become impossible to reason about. Reserve it for rare utility cases (like a .hidden { display: none !important; } helper). The better fix is almost always to:
- lower the specificity of the rule you're fighting (classes instead of ids), or
- make your rule match the same specificity and place it later.
Inheritance
There's one more way an element can get a style: from the element it sits inside. If you set a font on body, every paragraph and heading on the page uses it, even though no rule targets them directly. But not every property works like that:
<style>
body { font-family: Georgia, serif; color: #333; line-height: 1.6; }
.card { border: 2px solid #7a4b2a; padding: 1rem; }
</style>
<div class="card">
<h2>Arabica Gayo</h2>
<p>Text inherits the font and colour from body, but not the card's border or padding.</p>
</div>
- Inherited: text-related properties:
color,font-family,font-size,font-weight,line-height,text-align,visibility. - Not inherited: box properties:
border,padding,margin,background,width,display.
That's why you set the font once on body instead of on every element. A child can opt in explicitly with inherit (border: inherit;), and form controls are a common gotcha: buttons and inputs don't inherit fonts by default, so many stylesheets add button, input, select, textarea { font: inherit; }.
When rules conflict: higher specificity wins (ids > classes > types); with equal specificity, the later rule wins. Avoid ids and !important in stylesheets so specificity stays low and predictable. Text properties inherit; box properties don't.
Debugging a rule that "doesn't work"
Open developer tools (F12), select the element, and look at the Styles panel: it lists every matching rule in cascade order, with overridden declarations crossed out. The rule at the top is the winner, and its selector tells you how to beat it.
Why this matters for clean code
Predictable CSS comes from flat, low specificity: mostly single classes (.card-title, not #main .content div h2). Then source order alone decides conflicts, any rule can be overridden by a slightly later one, and you never need !important. The cascade stops being a fight and becomes a tool.
Recap
- Equal specificity → the later rule wins.
- Specificity: ids (1-0-0) > classes/attributes/pseudo-classes (0-1-0) > types (0-0-1); inline styles beat all selectors.
!importantoverrides everything else; avoid it.- Text properties inherit (
color,font-*,line-height); box properties don't (border,padding,margin,background). - Use developer tools to see which rule wins and why.