Specificity Hierarchy
Selectors carry different "weights", and every type of CSS selector holds a position in the specificity hierarchy. From strongest to weakest:
- Inline styles — top priority, overriding all other selectors.
- ID selectors (e.g.
#navbar) — next in priority, weighing 1-0-0. - Classes, attribute selectors, and pseudo-classes (e.g.
.test,[type="text"],:hover) — third in priority, weighing 0-1-0. - Element selectors and pseudo-elements (e.g.
<h1>,::before,::after) — low priority, weighing 0-0-1. - Universal selector (*) and :where() — no priority, weighing 0-0-0.
Understand the Weight Notation
A weight is written as three numbers (X-Y-Z), and each one counts a group of selectors:
- X — ID selectors.
- Y — class selectors, attribute selectors, and pseudo-classes.
- Z — element selectors and pseudo-elements.
Comparison starts on the left, so a higher leftmost number wins outright. On a tie, the next number decides, and so on.
Calculate the Specificity Weight
An element receives the CSS declaration whose specificity weight is the highest.
Example
Several selectors of different weights target the same paragraph here, which shows how the specificity hierarchy plays out. With a weight of 1-0-1, the highest of them, p#demo wins.
Output: complete HTML page
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CSS Specificity Weight</title>
<style>
#demo {color: blue;} /* weight: 1-0-0 */
p#demo {color: orange;} /* weight: 1-0-1 WINS! */
.test {color: green;} /* weight: 0-1-0 */
p.test {color: green;} /* weight: 0-1-1 */
p {color: red;} /* weight: 0-0-1 */
</style>
</head>
<body>
<p id="demo" class="test">Hello World!</p>
</body>
</html>
More Specificity Examples
The scenarios below show how specificity behaves in a few other situations, to help it sink in.
Equal specificity: the latest rule wins
When a rule appears twice in the style sheet, the one written last wins.
Output: complete HTML page
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Equal Specificity</title>
<style>
h1 {background-color: yellow;}
h1 {background-color: red;}
</style>
</head>
<body>
<h1>Hello World!</h1>
</body>
</html>
ID selectors beat attribute selectors
Even when an attribute selector targets the ID of the element, an ID selector outranks it on specificity, so the rule of the ID selector is the one applied.
Output: complete HTML page
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ID Selector vs Attribute Selector</title>
<style>
#myDiv {background-color: yellow;}
div[id=myDiv] {background-color: blue;}
</style>
</head>
<body>
<div id="myDiv">This div has id="myDiv".</div>
</body>
</html>
A class selector beats element selectors
Element selectors like <h1>, <p>, and <div> all lose to a class selector such as .intro.
Output: complete HTML page
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Class Selector vs Element Selector</title>
<style>
.intro {background-color: yellow;}
h1 {background-color: red;}
</style>
</head>
<body>
<h1 class="intro">Hello World!</h1>
</body>
</html>
The universal selector (*)
Because the universal selector (*) carries no specificity weight value, every other selector overrides it.
Output: complete HTML page
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Universal Selector Specificity</title>
<style>
* {background-color: yellow;}
h1 {background-color: red;}
</style>
</head>
<body>
<h1>Hello World!</h1>
</body>
</html>
Embedded style vs external style sheet
Given the same specificity, an embedded style sheet beats an external one when it is closer to the element, since it appears later.
/*From external CSS file:*/
#content h1 {background-color: red;}
/*In HTML file:*/
<style>
#content h1 {background-color: yellow;}
</style>