What is CSS Specificity?
CSS Specificity is the algorithm browsers use to decide which CSS rule wins when multiple rules target the same element. It's the reason your styles sometimes "don't work" even though the rule looks correct.
TL;DR
- 1.Specificity is a three-column score: (IDs, Classes, Elements). Higher left columns always win.
- 2.IDs beat classes, classes beat elements. No number of elements can outweigh a single class.
- 3.When specificity is equal, the last rule in source order wins.
- 4.
!importantoverrides all normal specificity, but creates maintenance nightmares. Avoid it.
Simple Explanation
Think of specificity like a sports scoring system with gold, silver, and bronze medals:
- Gold medals (IDs): One gold medal beats any number of silver or bronze medals.
- Silver medals (Classes, attributes, pseudo-classes): One silver medal beats any number of bronze medals.
- Bronze medals (Elements, pseudo-elements): The most common selectors, but the weakest.
When two CSS rules target the same element, count up the medals. The rule with more golds wins. If tied on golds, compare silvers. If tied again, compare bronzes. If everything ties, the rule that appears last in the CSS file wins.
Specificity Score Examples
The score is read left to right. A higher number in a left column always beats a higher number in a right column.
| Selector | Score (ID, Class, Element) | Why |
|---|---|---|
h1 | (0, 0, 1) | 1 element |
.btn | (0, 1, 0) | 1 class |
#header | (1, 0, 0) | 1 ID |
nav .link | (0, 1, 1) | 1 class + 1 element |
#nav .link.active | (1, 2, 0) | 1 ID + 2 classes |
div#app .btn:hover | (1, 2, 1) | 1 ID + 1 class + 1 pseudo-class + 1 element |
How It Works
Which rule wins?
/* (0, 1, 1) -- 1 class + 1 element */
nav .link {
color: blue;
}
/* (0, 0, 3) -- 3 elements */
header nav a {
color: red;
}
/* Winner: nav .link
1 class beats any number of elements */ID always wins over classes
/* (0, 5, 0) -- 5 classes */
.page .main .section .card .title {
font-size: 24px;
}
/* (1, 0, 0) -- 1 ID */
#page-title {
font-size: 16px;
}
/* Winner: #page-title
1 ID beats any number of classes */The Complete Hierarchy
From highest to lowest priority:
!important
Overrides everything (avoid using this)
Inline styles
style="..." attribute on the element
ID selectors
#header, #nav, #main
Class, attribute, pseudo-class selectors
.btn, [type="text"], :hover, :focus
Element, pseudo-element selectors
div, p, h1, ::before, ::after
Universal selector
* (zero specificity)
Common Mistakes
Don't
/* Using !important to force styles */
.btn {
color: red !important;
}
/* Now every override also needs
!important -- a war begins */Do
/* Increase specificity instead */
.header .btn {
color: red;
}
/* Or use a more specific class */
.btn--danger {
color: red;
}Don't
/* Using IDs for styling
(too high specificity) */
#submit-button {
background: blue;
}
/* Hard to override later */Do
/* Use classes for styling
(predictable specificity) */
.btn-primary {
background: blue;
}
/* Easy to override with another
class when needed */
See which CSS rules win on any element
Frontend Hero's CSS Scanner shows computed styles, matched selectors, and specificity for any element. Click once to see exactly which rules apply.
Try CSS Scanner →Browser Support
Specificity rules are part of the CSS specification since CSS1 and work identically in all browsers. The newer :where() and :is() pseudo-classes (which affect specificity) are supported in all modern browsers (Chrome 88+, Firefox 78+, Safari 14+).
Related Tools
Frequently Asked Questions
Specificity is calculated as a three-part score: (IDs, Classes, Elements). Count the number of ID selectors, class/attribute/pseudo-class selectors, and element/pseudo-element selectors. Compare each column left to right. For example, #nav .link has specificity (1, 1, 0) which beats .nav .link.active at (0, 3, 0) because the ID column wins.
!important doesn't change specificity -- it creates a separate layer of priority. A rule with !important beats any normal rule regardless of specificity. If two rules both have !important, normal specificity rules apply between them. Using !important is generally considered bad practice because it makes styles very hard to override later.
Inline styles (the style attribute on an HTML element) have a specificity of (1, 0, 0, 0) -- a fourth column that outranks any number of IDs in a stylesheet. This is by design: the style attribute is the most specific way to target one exact element. Only !important can override inline styles from a stylesheet.
:where() always has zero specificity regardless of what's inside it. :is() takes the specificity of its most specific argument. So :where(#id) has (0,0,0) specificity while :is(#id) has (1,0,0). Use :where() when you want easy-to-override defaults.
Use a methodology like BEM (Block-Element-Modifier) to keep specificity flat with single classes. Avoid ID selectors in stylesheets. Use CSS cascade layers (@layer) to control which styles take priority. Or use a utility-first framework like Tailwind CSS where specificity conflicts rarely arise because styles are applied directly via classes.
CSS Glossary
What is Flexbox?
One-dimensional layout model
What is CSS Grid?
Two-dimensional layout system
What is Z-Index?
Stacking order and contexts
What is Box-Sizing?
Control element sizing model
What is the CSS Cascade?
Rule priority and inheritance
What is Box Shadow?
Add depth with shadow effects
What is a CSS Reset?
Normalize browser defaults
What is Tailwind CSS?
Utility-first CSS framework
What is Responsive Design?
Adapt layouts to any screen