Skip to main content

Understanding specificity

· 7 min read
Luke Owen
Lead Front End Developer @ Lunio

Unless you’re building an incredibly simple site then you’re going to have some conflicts in your CSS, where multiple selectors give the same property to an element.

In this example, I’ve got two paragraphs with one class each, .red and .blue. But what if one element had both classes? What colour would it be?

Blue, if you reall want to know

The short version

Specificity is how the browser decides which styles are applied to an element. When styling rules conflict, the one that is more specific is considered to be more relevant.

How it works

Each CSS selector has a specificity weighting; the browser calculates the weighting of all the selectors in a given rule to find the specificity for that ruleset.

These principles are then used to decide the styling:

  • When two rules conflict, the highest specificity wins.
  • When two rules have identical specificity, the last one to be declared in the CSS wins.

And now for the long version…

A few basics

Before we get into how specificity weights are calculated, there are a few basic principles that always apply.

Last selector wins

Super simple: when two or more rules have equal specificity, the lowest one is the more specific.

In the example I gave above, the red and blue classes have equal specificity. In this case, the text would be blue because blue is declared second.

/* An element with both classes would be blue */
.red {
color: red;
}

.blue {
color: blue;
}

Also worth noting that the last selector only wins when it comes to conflicts. So in the example below the text would still be blue, but there would be a 2px black border because .blue only overrides .red when it comes to the color property.

/* An element with both classes would be blue and have a black border */
.red {
border: 2px solid black;
color: red;
}

.blue {
color: blue;
}

Direct selector beats inheritance

CSS is supposed to be cascading, with elements pulling styling from their parents. A ruleset that specifically targets an element will always beat styling that’s inherited from a parent.

<style> tags beat stylesheets

Embedded styles through a HTML &#60;style> tag are considered more specific than an external stylesheet.

Calculating specificity

To calculate specificity for a rule we can give a score to each individual selector in that rule. By adding the scores we can find how specific the rule is.

A blank specificity score is 0,0,0,0 – each CSS selector increments one of the four categories by one point.

If it’s easier you can remove the commas and treat the specificity score as a regular number. It most cases this is fine, just remember that it’s not really a number: it’s perfectly possible (and utterly horrifying) to have a score like 0,4,22,46.

In specificity the highest leftmost value will always win, so a specificity score of 0,1,0,0 will beat 0,0,10,0. It doesn’t matter how high the third category is: it can’t beat a higher score in the second category.

Specificity scores are calculated as:

Universal selector (*): 0,0,0,0

Yup, the asterisk is worth absolutely nothing and will be overridden by anything else.

/* 0,0,0,0 */
* {}

Elements and pseudo-elements: 0,0,0, 1

/* 0,0,0,1 */
p {}

/* 0,0,0,2 (one for the p and one for :before) */
p:before {}

Classes, attributes, and pseudo-classes: 0,0,1,0

The exception here is :not() which doesn't provide any specificity by itself. But the selector inside the brackets will add to the specificity count.

/* 0,0,1,0 */
.red {}

/* 0,0,1,0 */
[type="button"] {}

/* 0,0,2,0 (one for the class and one for :hover) */
.red:hover {}

/* 0,0,1,1 (:not doesn't count, but its selector does) */
.red:not(p) {}

ID’s: 0,1,0,0

/* 0,1,0,0 */
#red {}

Inline styles: 1,0,0,0

<!-- 1,0,0,0 -->
<div style="color: red;">lorem</div>

Some examples

Aaaand put them all together:

/* 0,0,1,3 */
.header nav a svg {}

/* 0,0,2,0 */
[data-language="html"] .lorem {}

/* 0,1,1,2 */
#sidebar div + span:focus {}

/* 0,0,0,1 */
div * {}

!important ☢️

Using !important is the nuclear option, it overrides all other specificity and tells the browser to apply this rule. Essentially it’s a ‘win’ button.

The text here is red, despite blue having higher specificity.

If multiple rules use !important then the usual rules of specificity apply to them. In this example the text is blue (it’s declared after red), and green is totally ignored because it’s not !important (sorry green!)

Using !important is pretty dangerous, it starts a snowball effect where you’ll start to use it more and more to override previously declared !important rules.

It’s the nuclear option for a reason, under normal circumstances you shouldn’t be using it.

So it’s never okay?

There are a couple of times where I consider it acceptable to use an !important tag:

Overriding a library

You can’t control the specificity of external libraries, sometimes they’ll mess with your styling and you’ll need to override them. You can either copy their selector and then make it more specific, which can get a bit crazy. Or you can throw an important tag at it.

Utility classes

Most projects I start have a utility style sheet somewhere, this is just a bunch of CSS for basic repetitive styling like floats and padding. These need to work consistently and not break if I accidentally create a more specific selector.

My spacing-css library uses important on all of its classes since it’s always supposed to override the local stylesheet.

.margin-top {
margin-top: 10px !important;
}

Some things to remember

Selectors should be as simple as possible

If you write big and complicated selectors then when you want to override them you’ll need to write bigger and more complicated ones.

It ends up as a bit of a CSS arms race until you decide to use !important and everything kind of goes to hell.

Selectors that are short and simple will be easier to maintain in the future.

Classes can be doubled

In CSS it’s perfectly valid to repeat a class selector to increase specificity, so .red.red has higher specificity than .red

Obviously, at some point this gets silly, if you have to repeat a class more than a few times then you need a more specific selector.

In this example the .blue class is twice as specific as .green

/* 0,0,2,0 */
.blue.blue {
color: blue;
}

/* 0,0,1,0 */
.green {
color: green;
}

The HTML order doesn't make a difference

Markup has no bearing on specificity. It doesn't matter what order your HTML classes are, their order in the CSS is what counts.

In the example below the two elements have identical styling

<div class="red blue">lorem</div>
<div class="blue red">ipsum</div>