Skip to content
Laviyx Learn

Try

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.

Beginner6 min readUpdated
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#

CSS
p { color: blue; }
.intro { color: green; }
p { color: red; }
HTML
<p class="intro">What colour am I?</p>
Result

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:

  1. Origin and importance: your stylesheets beat the browser's defaults. !important declarations jump ahead (more below).
  2. Cascade layers: when you use @layer, later layers win, and styles not in any layer beat all layered styles (see Organizing CSS).
  3. Specificity: the more specific selector wins.
  4. 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):

Selector partAdds to
ID: #navids
Class .btn, attribute [type="text"], pseudo-class :hoverclasses
Element p, pseudo-element ::beforeelements
Universal * and combinators (>, +, ~, space)nothing

Compare the numbers from left to right. One id beats any number of classes; one class beats any number of elements.

SelectorSpecificity
p(0, 0, 1)
ul li(0, 0, 2)
.card(0, 1, 0)
p.note(0, 1, 1)
.nav a:hover(0, 2, 1)
#header .logo(1, 1, 0)
#header #logo(2, 0, 0)
CSS
#main p { color: purple; }     /* (1, 0, 1) */
.content .text { color: teal; } /* (0, 2, 0) */
HTML
<div id="main" class="content">
  <p class="text">One id beats two classes, so I am purple.</p>
</div>
Result

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-title instead 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:

CSS
.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:

InheritedNot inherited
color, font-family, font-size, font-weight, line-height, text-align, letter-spacing, visibility, cursor, list-stylemargin, padding, border, width, height, background, display, position
CSS
.panel {
  color: #1d3b4f;
  font-family: Georgia, serif;
  border: 2px solid #1d3b4f;
  padding: 8px;
}
HTML
<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>
Result

That is why you set font-family once on body and the whole page uses it.

Controlling inheritance#

ValueMeaning
inheritUse the parent's value, even for non-inherited properties
initialUse the property's initial value from the CSS specification
unsetinherit for inherited properties, initial for the rest
revertGo back to the browser's default style for that element
CSS
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:

CSS
p { color: black; }
.box p { color: blue; }
p.special { color: green; }
#hero p { color: orange; }
HTML
<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
CSS
p { color: black; }
.box p { color: blue; }
p.special { color: green; }
#hero p { color: orange; }
HTML
<div class="box"><p>One</p><p class="special">Two</p></div>
<div id="hero" class="box"><p class="special">Three</p></div>
Result
  • One is blue: .box p (0, 1, 1) beats p (0, 0, 1).
  • Two is green: .box p and p.special are 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?