CSS Specificity Explained: How Browsers Decide Which Styles Win
What is CSS Specificity?
CSS specificity is a system that determines which CSS rule takes priority when multiple rules target the same element. When two or more conflicting styles apply to an element, the browser uses specificity to decide which style wins.
Why Specificity Matters
Understanding specificity is crucial because it explains why some of your CSS styles seem to be "ignored" by the browser. Most CSS debugging problems come down to specificity conflicts.
/* Which color will the paragraph be? */
p { color: blue; }
.intro { color: green; }
#welcome { color: red; }<p class="intro" id="welcome">Hello World</p>The paragraph will be red because the ID selector has the highest specificity.
The Specificity Hierarchy
CSS specificity is calculated based on the types of selectors used. Think of it as a scoring system with four levels:
Level 1: Inline Styles (Highest)
Inline styles written directly on an HTML element have the highest specificity.
<p style="color: red;">This will always be red</p>Level 2: ID Selectors
ID selectors, such as #header or #main-content, carry a very high level of specificity.
#header { color: blue; }Level 3: Class, Attribute, and Pseudo-Class Selectors
These include .classname, [attribute], :hover, :first-child, etc.
.nav-link { color: green; }
[type="text"] { border: 1px solid gray; }
a:hover { color: orange; }Level 4: Element and Pseudo-Element Selectors (Lowest)
These include p, div, h1, ::before, ::after, etc.
p { color: black; }
h1 { font-size: 2rem; }Calculating Specificity
Specificity is often represented as a four-part value: (inline, IDs, classes, elements)
/* (0, 0, 0, 1) - one element */
p { }
/* (0, 0, 1, 0) - one class */
.intro { }
/* (0, 1, 0, 0) - one ID */
#header { }
/* (0, 0, 1, 1) - one class + one element */
p.intro { }
/* (0, 1, 1, 1) - one ID + one class + one element */
div#header.active { }
/* (0, 0, 2, 1) - two classes + one element */
ul.nav .nav-item { }Specificity Rules in Practice
Rule 1: Higher specificity always wins
.card .title { color: blue; } /* (0,0,2,0) */
.title { color: red; } /* (0,0,1,0) */
/* Blue wins - higher specificity */Rule 2: Equal specificity - last one wins
.title { color: blue; } /* (0,0,1,0) */
.title { color: red; } /* (0,0,1,0) */
/* Red wins - it comes last */Rule 3: !important overrides everything
.title { color: red !important; }
#header .title { color: blue; }
/* Red wins - !important overrides specificity */The Universal Selector and Combinators
The universal selector (*), combinators (>, +, ~), and the :not() pseudo-class do NOT add to specificity.
* { } /* (0,0,0,0) */
div > p { } /* (0,0,0,2) - only div and p count */
:not(.active) { } /* (0,0,1,0) - only .active counts */Avoiding Specificity Wars
Here are best practices to avoid specificity conflicts:
- Use classes instead of IDs for styling
- Keep selectors short and simple
- Avoid !important unless absolutely necessary
- Use a consistent naming pattern, such as BEM (Block Element Modifier).
- Use a logical source order in your stylesheet
/* BAD: Too specific, hard to override */
div#main-content ul.nav li.nav-item a.nav-link { color: blue; }
/* GOOD: Simple and maintainable */
.nav-link { color: blue; }Summary
CSS specificity determines which styles are applied when multiple rules conflict. Remember the hierarchy: inline styles > IDs > classes > elements. Keep your selectors simple, prefer classes over IDs, and avoid !important to write maintainable CSS that is easy to debug and override.