The Basic Guide to CSS Specificity

CSS Specificity is what decides what styles are applied to elements; the more specific the CSS selector, the more weight it has in determining the style of an element.

Take the following HTML and CSS as an example:

<article id="css-rocks">
...
</article>
<style>
#css-rocks {
background-color: white;
}
article {
background-color: black;
}
</style>

Q: What background color will the article element have?

A: White, since the CSS selector the white background color is more specific.

To see this in action, the element inspector will show you all the styles applied to an element in the order of specificity.

In Chrome, the Styles portion of the Elements tab orders styles based on their specificity and crosses out styles that get overwritten by more specific selectors

There are five main levels that determine a style’s specificity and it all has to do with the syntax used in the selector. They are, in order of least-specific to most-specific:

Element Selectors

These are styles using just the element as the selector:

article {
background-color: black;
}

Class Selectors

Styles that use a class in the selector:

.css-class {
background-color: black;
}

ID Selectors

Styles that use an ID in the selector:

#css-id {
background-color: black;
}

The three shown above are the most common, but there are two more levels that delve into the evil and dark arts…

Inline Selectors

These are styles directly within the HTML applied as an attribute:

<article style="background-color: black;"> ... </article>

And finally, the one that beats them all…

!important Selectors

If an individual style is declared to be !important, then it will override anything else:

article {
background-color: black !important;
}

With that foundation, there’s one more concept to tack on top: Selectors can use a combination of attributes, so CSS uses a weight system to compute final specificity. Let’s use one more example:

<article id="css-rocks">
<section class="css-history">
...
</section>
</article>
<style>
#css-rocks section {
background-color: black;
}
article#css-rocks section.css-history {
background-color: white;
}
</style>

There are two CSS selectors with two different weights. Let’s go through how to calculate a CSS weight:

  1. Since five different factors influence CSS specificity, we use five numbers to track how many times we see a type of selector. We start the weight with zero specificity, which is represented as (0, 0, 0, 0, 0). Each digit represents (# of !important, # of inline styles, # of IDs, # of classes, # of elements).
  2. Using the selector #css-rocks sectionas our first example, count each type of selector and add it to the weights. The first thing we see is #css-rocks, an ID selector. Our weight is now (0, 0, 1, 0, 0). Next we see an element selector, our weight is now (0, 0, 1, 0, 1). That was the last item in the selector, so we have our final weight. The style background-color: black; has a weight of (0, 0, 1, 0, 1).

Let’s do that one more time with the other selector. We start with (0, 0, 0, 0, 0) and are considering the selector article#css-rocks section.css-history. Considering each attribute from left-to-right:

Selector      | Type        | Resulting CSS Selector Weight
article | Element | (0, 0, 0, 0, 1)
#css-rocks | Id | (0, 0, 1, 0, 1)
section | Element | (0, 0, 1, 0, 2)
.css-history | Class | (0, 0, 1, 1, 2)

We now have the two weights for those background-color styles, which we can represent as:

(0, 0, 1, 0, 1) background-color: black;
(0, 0, 1, 1, 2) background-color: white;

Both selectors have a 1 in the ID slot — a tie. The CSS weight then falls down to the class slot to determine a winner. Since the second selector uses a class and the first does not, the second selector is more specific and thus “wins.”

That’s the basic idea of CSS Specificity, but there are a few more loose ends…

Q: What happens if two styles have the same specificity?

A: Whichever is declared later wins. For example:

article {
background-color: black;
}
article {
background-color: white;
}

Both styles have a specificity of (0, 0, 0, 0, 1), but the background-color: white; comes later in the stylesheet, so it wins.

Q: Does the !important attribute apply to all styles in a selector or just the one?

A: Just what it’s applied on. As an example, here’s a selector with each style’s specificity to the right of it:

article .css-history {
background-color: black !important; /* (1, 0, 0, 1, 1) */
color: white; /* (0, 0, 0, 1, 1) */
}

Specificity is a property on each CSS style, not the selector. It just happens to be that when !important isn’t used, styles in a selector will all have the same weight.

Q: I really need to override a selector, how should I do that?

A: This is contextual and unique to each situation, but I try to follow this checklist:

  1. Is it possible to make the style you’re trying to override less specific? I sometimes use IDs in selector when they aren’t necessary and removing those will make overriding them possible by, for example, adding an extra class.
  2. Should the style you’re trying to override even live in the original selector? When I make a CSS component, I may set a style on the base component that doesn’t belong there. For example, if I make a .card component, I may initially believe all cards will have a white background, only to find down the line I want cards with either white or off-white backgrounds. I would remove the background color style from .card and use some .white-background or .offwhite-background helper classes to set the card’s background color.
  3. Should the overriding selector use the same chain of attributes as the one that already exists? Going off the example above, consider you have a card component you use in your website’s articles. The selector may look something like article .card. If you want to have another type of card with rounded corners, it makes sense to make a selector with article .card.card-rounded.
  4. Is this a quick-fix situation that requires an immediate (read: ugly) solution? Sometimes you need to fix a bug in prod or that demo that’s being shown in 15 minutes. The easiest and most-obviously-evil solution is to just slap an !important on the style. Another option is to search for attributes (preferably IDs) that you can add to the selector to bump up its specificity, e.g. html body #content-wrapper article#css-rocks. I prefer the former option since !important jumps out immediately as tech debt that needs to be addressed, whereas the latter may live on without raising too much of a code smell. Either way, these aren’t long-term solutions — Fix them when you have more time.

Q: I want to cause other people frustration and confusion. Any tips?

A: There’s nothing stopping you from reusing the same IDs and classes in your selectors to bump up their style’s specificity:

#css-rocks#css-rocks {
background-color: black; /* (0, 0, 2, 0, 0) */
}
#css-rocks {
background-color: white; /* (0, 0, 1, 0, 0) */
}

Q: You don’t understand. I hate everyone who has to maintain my code after me. What should I do?

A:

<article style="background-color: banana !important;">
...
</article>

You literally cannot override this in CSS. You need to edit the HTML or use Javascript.