On this page
Specificity: how CSS decides which style wins
How does CSS decide which style to apply?
When multiple CSS rules target the same element, the browser needs a system to decide which one wins. That system is called the cascade and is based on three factors, evaluated in this order:
- Origin and importance (user styles, author styles, browser styles)
- Specificity of the selector
- Order of appearance in the code
What is specificity?
Specificity is a numeric value that the browser assigns to each CSS selector. It is represented as a tuple of three numbers: (ID, Class, Element).
| Selector | ID | Class | Element | Value |
|---|---|---|---|---|
p |
0 | 0 | 1 | (0,0,1) |
.card |
0 | 1 | 0 | (0,1,0) |
p.card |
0 | 1 | 1 | (0,1,1) |
#hero |
1 | 0 | 0 | (1,0,0) |
#hero .card p |
1 | 1 | 1 | (1,1,1) |
Each column is compared from left to right. A single ID (1,0,0) outweighs a hundred classes (0,100,0) because the ID column is evaluated first.
What counts as a "class"?
The class column includes:
- Class selectors (
.card) - Attribute selectors (
[type="text"]) - Pseudo-classes (
:hover,:focus,:nth-child())
What counts as an "element"?
The element column includes:
- Type selectors (
div,p,h1) - Pseudo-elements (
::before,::after,::placeholder)
The universal selector and combinators
The universal selector (*), combinators (>, +, ~, ), and the :where() pseudo-class have zero specificity. They add nothing.
/* Both have specificity (0, 1, 0) */
.card { color: red; }
*.card { color: blue; } /* Same specificity */The :is() and :not() pseudo-classes
Unlike :where(), the :is() and :not() pseudo-classes take the specificity of their most specific argument.
/* Specificity: (1, 0, 0) because of #hero inside :is() */
:is(#hero, .card, p) {
color: red;
}The cascade: order of appearance
When two selectors have the same specificity, the one that appears last in the source code wins.
.title { color: blue; }
.title { color: red; } /* Wins: appears later */Cascade layers with @layer
Modern CSS introduces @layer to control priority without depending on the physical order of the code. Layers declared later have higher priority.
@layer base, components, utilities;
@layer base {
.button { padding: 0.5rem; }
}
@layer utilities {
.button { padding: 1rem; } /* Wins because it is a later layer */
}Inline styles and !important
Inline styles (style="...") override any selector in the stylesheet. Only !important can override them, but excessive use makes maintenance difficult.
The complete priority, from lowest to highest, is:
- Browser styles (user-agent)
- Author styles (your CSS)
- Author styles with
!important - Inline styles
- Inline styles with
!important
Recommended strategy
To keep CSS predictable:
- Use classes as the basis for your selectors
- Avoid IDs for styling (reserve them for JavaScript or anchors)
- Avoid
!importantexcept for very specific utilities - Use
@layerto organize priority between base, components, and utilities - Keep selectors simple: one level of class is usually enough
Now that you understand how CSS resolves conflicts, in the next lesson we will explore the box model, the foundation of all layout in CSS.
Practice
- Calculate specificity: Write five different selectors that target the same element and rank them from lowest to highest specificity. Verify your calculation using the browser inspector.
- Organize with @layer: Create three layers (
base,components,utilities) with@layerand define conflicting rules in each. Confirm that the layer declared last has higher priority. - Eliminate an !important: Find a case where you need
!importantand refactor the selectors so the correct style wins through specificity or cascade order alone.
/* Specificity: (0, 0, 1) */
p {
color: black;
}
/* Specificity: (0, 1, 0) */
.message {
color: blue;
}
/* Specificity: (0, 1, 1) */
p.message {
color: green;
}
/* Specificity: (1, 0, 0) */
#alert {
color: red;
}
/* Specificity: (0, 2, 0) - greater than (0, 1, 1) */
.container .message {
color: purple;
}
/* Both selectors have the same
specificity: (0, 1, 0) */
.button {
background-color: blue;
color: white;
}
/* This one wins by order: it comes later */
.button {
background-color: green;
}
/* Use layers to control priority */
@layer base, components, utilities;
@layer base {
.button { background: gray; }
}
@layer components {
.button { background: blue; }
}
@layer utilities {
.button { background: green; } /* Wins */
}
Sign in to track your progress