CSS course menu
CSS Cascade, Specificity and Inheritance Explained
Understand how CSS decides which style wins: the cascade (origin, importance, layers, specificity, order), how to calculate specificity for ids, classes and elements, which properties are inherited, inherit/initial/unset, and why to avoid !important.
On this page
When two rules set the same property on the same element, only one value can win. CSS decides with three ideas: the cascade, specificity and inheritance. Understanding them explains almost every "why is my CSS not working?" moment.
A conflict#
p { color: blue; }
.intro { color: green; }
p { color: red; }<p class="intro">What colour am I?</p>The paragraph is green, even though color: red comes last. The class selector is more specific than the element selector, and specificity is checked before order.
How the cascade decides#
For each property, the browser compares the competing declarations in this order, stopping at the first step that has a winner:
- Origin and importance: your stylesheets beat the browser's defaults.
!importantdeclarations jump ahead (more below). - Cascade layers: when you use
@layer, later layers win, and styles not in any layer beat all layered styles (see Organizing CSS). - Specificity: the more specific selector wins.
- Order of appearance: if everything else is equal, the last declaration wins.
Inline style attributes beat any selector in a stylesheet (except !important).
Specificity#
Specificity is counted as three numbers, often written as (ids, classes, elements):
Compare the numbers from left to right. One id beats any number of classes; one class beats any number of elements.
#main p { color: purple; } /* (1, 0, 1) */
.content .text { color: teal; } /* (0, 2, 0) */<div id="main" class="content">
<p class="text">One id beats two classes, so I am purple.</p>
</div>Keep specificity low#
High-specificity selectors are hard to override, which leads to even more specific selectors, and eventually !important everywhere. Good habits:
- Style with classes, not ids.
- Keep selectors short:
.card-titleinstead of#main .content div.card h2. - Use
:where(), which has zero specificity, for defaults that should be easy to override (Modern Selectors).
!important#
Adding !important to a declaration makes it win over normal declarations, regardless of specificity:
.hidden { display: none !important; }It is a blunt tool: the only way to beat it is another !important with higher specificity. Reasonable uses are rare, such as utility classes that must always apply. Avoid it as a fix for specificity problems; fix the selectors instead.
Inheritance#
Some properties are inherited: if you set them on an element, its descendants get the same value unless they set their own. Most text properties are inherited; most box properties are not:
.panel {
color: #1d3b4f;
font-family: Georgia, serif;
border: 2px solid #1d3b4f;
padding: 8px;
}<div class="panel">
<h3>Inherited font and colour</h3>
<p>The heading and this paragraph inherit the colour and font, but they do not get their own border or padding.</p>
</div>That is why you set font-family once on body and the whole page uses it.
Controlling inheritance#
button { font: inherit; } /* buttons do not inherit fonts by default */Practice#
Practice exercise
Without running it, decide the colour of each paragraph, then check with the preview:
p { color: black; }
.box p { color: blue; }
p.special { color: green; }
#hero p { color: orange; }<div class="box"><p>One</p><p class="special">Two</p></div>
<div id="hero" class="box"><p class="special">Three</p></div>Show solution
p { color: black; }
.box p { color: blue; }
p.special { color: green; }
#hero p { color: orange; }<div class="box"><p>One</p><p class="special">Two</p></div>
<div id="hero" class="box"><p class="special">Three</p></div>- One is blue:
.box p(0, 1, 1) beatsp(0, 0, 1). - Two is green:
.box pandp.specialare both (0, 1, 1), so the later rule wins. - Three is orange:
#hero p(1, 0, 1) has an id, which beats everything else.
Key takeaway#
Finished this lesson?