Quick Answer
The selector #header .nav a has a specificity of (1, 1, 1). The selector .sidebar .widget h3 has a specificity of (0, 2, 1). An ID selector always outweighs any number of classes.
CSS Selector
Common Examples
| Input | Result |
|---|---|
| #header .nav a | (1, 1, 1) - score 111 |
| .sidebar .widget h3 | (0, 2, 1) - score 21 |
| div p | (0, 0, 2) - score 2 |
| #main #content .article h1 | (2, 1, 1) - score 211 |
| a:hover | (0, 1, 1) - score 11 |
How It Works
CSS specificity is the algorithm browsers use to determine which CSS declaration applies when multiple rules target the same element. It is calculated from the selector and expressed as a three-part value (a, b, c).
The Three Categories
a: ID selectors count the number of #id selectors. Each ID contributes 1 to the first position.
b: Class-level selectors count the number of .class selectors, [attribute] selectors, and pseudo-classes like :hover, :focus, :nth-child(), etc. Each one contributes 1 to the second position.
c: Element-level selectors count the number of type selectors (div, p, h1) and pseudo-elements (::before, ::after, ::first-line). Each one contributes 1 to the third position.
Comparison Rules
Specificity is compared left to right. A selector with (1, 0, 0) always beats (0, 99, 99) because the first column (IDs) is compared first. If the first column ties, the second column is compared, and so on. If all columns are equal, the rule that appears later in the source wins.
Special Cases
- The universal selector (
*) has zero specificity - Combinators (
>,+,~, space) do not affect specificity :not()itself adds no specificity, but the selector inside it does:where()and its contents have zero specificity:is()and:has()take the specificity of their most specific argument- Inline styles override all selector-based specificity (conceptually a fourth column)
- !important overrides everything, including inline styles
Worked Example
For the selector #main .content ul > li.active a:hover:
- IDs:
#main= 1 - Classes and pseudo-classes:
.content,.active,:hover= 3 - Elements:
ul,li,a= 3
Specificity = (1, 3, 3), score = 133.
Compared to .sidebar .widget .list a which has specificity (0, 3, 1), score = 31. The first selector wins because it has 1 ID vs 0 IDs, regardless of the other columns.
Practical Tips
To keep specificity manageable, avoid deeply nested selectors and limit ID usage in CSS. Many methodologies like BEM (Block Element Modifier) use only class selectors, keeping all specificity at the (0, n, 0) level. This makes the cascade predictable and overrides straightforward.
Related Calculators
Frequently Asked Questions
Why does one ID beat any number of classes?
How does !important interact with specificity?
!important overrides the normal specificity cascade entirely. An !important declaration on a low-specificity rule beats a high-specificity rule without !important. When multiple !important declarations compete, normal specificity rules apply among them. Using !important frequently leads to difficult-to-maintain CSS.
Do pseudo-elements and pseudo-classes have the same specificity?
:hover, :focus, :nth-child()) count as class-level selectors in column b. Pseudo-elements (::before, ::after, ::first-line) count as element-level selectors in column c. A pseudo-class has higher specificity weight than a pseudo-element.
What is the specificity of inline styles?
style attribute on an HTML element) override all selector-based specificity. They are conceptually in a fourth column that outranks IDs. Only !important can override an inline style. In practice, avoid inline styles when possible to keep styles maintainable.
How does the :where() pseudo-class affect specificity?
:where() pseudo-class and everything inside it has zero specificity. This makes it useful for writing default styles that are easy to override. For example, :where(.card) h2 has specificity (0, 0, 1) because the .card inside :where() contributes nothing. Without :where(), .card h2 would have specificity (0, 1, 1).
CalculateY