Skip to main content

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.!important overrides 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.

SelectorScore (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:

1

!important

Overrides everything (avoid using this)

2

Inline styles

style="..." attribute on the element

3

ID selectors

#header, #nav, #main

4

Class, attribute, pseudo-class selectors

.btn, [type="text"], :hover, :focus

5

Element, pseudo-element selectors

div, p, h1, ::before, ::after

6

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 */
Frontend Hero

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+).

Frequently Asked Questions

How is CSS specificity calculated?

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.

Does !important override specificity?

!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.

Why is inline style specificity higher than ID selectors?

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.

What is the specificity of :where() and :is()?

: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.

How do I avoid specificity wars in large projects?

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.