On this page
CSS Specificity Explained
What Is CSS Specificity?
CSS specificity is the algorithm browsers use to decide which rule wins when several rules target the same element and set the same property. If you ever wondered why your style is ignored, the answer is almost always specificity. Our focus keyword is CSS specificity, and along the way we cover trending questions: how to calculate CSS specificity, CSS specificity hierarchy, CSS specificity vs order, why is my CSS not working, CSS specificity calculator, and how @layer and :where() reduce specificity problems.
The Specificity Scoring Model
Think of specificity as a three-part score written (A, B, C). Compare the parts from left to right, and the first difference decides the winner. Never treat it as a decimal number: 11 classes never beat one ID.
| Column | Counts | Examples |
|---|---|---|
| A | ID selectors | #header |
| B | Class selectors, attribute selectors, pseudo-classes | .card, [type='text'], :hover, :nth-child() |
| C | Type selectors and pseudo-elements | div, p, ::before |
The universal selector * and combinators (+, >, ~, and the space) add nothing. Inline styles (the style attribute) beat every selector-based rule, and !important sits in a different level of the cascade (covered in the next lesson).
Worked Examples
p /* (0,0,1) */
p.intro /* (0,1,1) */
#main p.intro /* (1,1,1) */
ul li a:hover /* (0,1,3) */
.nav .item.active /* (0,3,0) */
#a #b /* (2,0,0) */
* {} /* (0,0,0) */Comparison: .a.b.c.d.e is (0,5,0), and #x is (1,0,0). The ID wins because column A is compared first.
What Happens When Specificity Is Equal?
If two rules have identical specificity, the rule that appears later in the source order wins. This is why the order of your stylesheets matters, and why link order in HTML can change results.
Functional Pseudo-classes and Specificity
:is(),:not()and:has()take the specificity of their most specific argument. So:is(#a, .b)is(1,0,0).:where()always contributes zero.:nth-child(2n+1 of .item)counts as one pseudo-class plus the most specific selector in theoflist.- With native CSS nesting, the
&behaves like:is()of the parent selector list, so it inherits the parent's most specific selector.
Common Specificity Traps
- Overusing IDs for styling. They are hard to override later. Prefer classes.
- Deep descendant chains like
.sidebar .widget ul li a. They are fragile and hard to override. - Inline styles from JavaScript libraries, which can only be beaten by
!important. - Third-party CSS that uses high-specificity selectors.
- Escalation by !important, where each fix requires another
!important.
Strategies to Keep Specificity Low
- Use a single class for styling (BEM-style naming such as
.card__title). - Avoid qualifying classes with element names, for example use
.buttonnota.button. - Use
:where()for base styles so components can override them easily. - Use cascade layers (
@layer) to control priority regardless of specificity between layers. - Order your CSS from generic to specific: reset, base, layout, components, utilities.
- Increase specificity intentionally and minimally when needed, for example doubling a class:
.btn.btn(a known hack, but layers are cleaner).
Debugging Specificity in DevTools
- Right-click the element and choose Inspect.
- In the Styles panel, look for rules that are struck through. These lost the cascade.
- Hover over a selector to see its specificity in Chrome or Firefox tooltips.
- Check the Computed tab and click the arrow next to a property to see which rule provided the final value.
Specificity Cheat Sheet
Inline style > ID > class / attribute / pseudo-class > element / pseudo-element
Equal specificity -> last rule in source order wins
:where() -> always 0
:is() :not() :has() -> most specific argumentBest Practices
- Write flat, low-specificity selectors and rely on source order and layers.
- Never fix a specificity problem by adding an ID or
!importantfirst. - Document any intentional specificity boosts with a comment.
- Use a linter (Stylelint) with rules like
selector-max-idandselector-max-specificity.
Summary
Specificity is just a scoring system: IDs, then classes, then elements, then source order. Keep it flat, understand how :is() and :where() behave, and use layers for scalable projects. Play with the examples below to see the winner change live.
Press Run to execute.
Press Run to execute.
Press Run to execute.
Press Run to execute.
Press Run to execute.
For each selector in the comment block, write its specificity as (A,B,C) in the console output by completing the object. Then explain which selector would win for a link with class 'nav-link' inside an element with id 'menu'.
Press Run to execute.
Show expected output
{ s1: '(0,0,1)', s2: '(0,1,0)', s3: '(1,0,1)', s4: '(1,2,0)' }This is a self-check — compare your result with the expected output above.
The button should be green, but a more specific rule keeps it blue. Change ONLY the CSS (no !important, no inline styles, no IDs) so the button becomes green.
Press Run to execute.
Show expected output
The Save button has a green background.This is a self-check — compare your result with the expected output above.
Was this page helpful?