CSS stands for Cascading Style Sheets. “Cascading” means styles are applied according to a set of priority rules. Understanding those rules means you stop being surprised when a style doesn’t take effect.
Three sources of styles
The browser gathers styles from three sources, in ascending order of priority:
- Browser defaults (user agent stylesheet) — built-in styles:
<h1>is large,<a>is blue. - Your styles (author stylesheet) — what you write.
- Inline styles (
style="") — highest priority among normal styles.
Specificity: the formula
When two rules target the same element, the more specific one wins. Specificity is written as a triplet (a, b, c):
| Type | Contribution | Example |
|---|---|---|
ID (#) |
a = 1 | #header → (1,0,0) |
Class (.), pseudo-class, attribute |
b = 1 | .card → (0,1,0) |
| Tag, pseudo-element | c = 1 | h1 → (0,0,1) |
Each type is counted independently. Comparison goes left to right.
Calculation examples
p { color: black; } /* (0,0,1) */
.post-text { color: gray; } /* (0,1,0) */
#main p { color: blue; } /* (1,0,1) */
.post .text p { color: green; } /* (0,2,1) */
For <p class="post-text"> inside <div id="main">:
- p → (0,0,1)
- .post-text → (0,1,0)
- #main p → (1,0,1) — winner (first number is larger)
Declaration order: when specificity is equal
If two rules have the same specificity, the one declared later wins.
.btn { background: #2563eb; } /* declared first */
.btn { background: #1d4ed8; } /* declared later — wins */
This matters when linking multiple CSS files: the order of <link> tags counts.
Inheritance
Some properties are automatically inherited from parent to child:
body {
font-family: 'Inter', sans-serif;
color: #374151;
line-height: 1.6;
}
All elements inside <body> will inherit font-family, color, and line-height — no need to repeat them for every tag.
Inherited properties: color, font-*, line-height, text-align, list-style, cursor.
NOT inherited: width, height, padding, margin, border, background, display.
!important — the last resort
.btn {
color: white !important;
}
!important overrides any specificity. It looks like a solution but creates problems:
- The rule becomes hard to override later
- When
!importantappears often, the code becomes chaotic - It signals that the CSS structure is poorly designed
When it’s justified: overriding third-party library styles that also use !important.
In the DevBlog, avoid !important. Raise specificity in another way instead.
Debugging the cascade in DevTools
Open DevTools (F12), select an element, and open the Styles tab:
- Crossed-out properties have been overridden by another rule
- The browser shows which selector won and which file it came from
Common mistakes
Style not applied — low specificity
/* You wrote this */
a { color: #2563eb; }
/* But reset.css has */
nav a { color: inherit; } /* (0,1,1) > (0,0,1) — reset wins */
Fix: raise the specificity of your rule.
.site-nav a { color: #2563eb; } /* (0,1,1) — equal specificity, but later */
File order
<!-- Your styles first, then the library — the library will override you -->
<link rel="stylesheet" href="style.css">
<link rel="stylesheet" href="bootstrap.min.css">
<!-- Correct: library first, then your styles -->
<link rel="stylesheet" href="bootstrap.min.css">
<link rel="stylesheet" href="style.css">
Summary: priority order
From lowest to highest:
- Browser default styles
- External CSS (by link order, then by specificity)
- Inline
style="" !important
Once you know these rules, you can explain the behavior of any CSS rule in your project.
💬 Comments (0)
No comments yet
Be the first to share your opinion about this article!