What is CSS Specificity and How Does it Work?

Learn how CSS styles are applied to elements based on their classes and IDs

Yogesh Chavan
Level Up Coding

--

Photo by Goran Ivos on Unsplash

CSS stands for Cascading Style Sheet. This means that the styles flow through the entire application and are applied to elements with the matching identifiers. Since CSS is a global styling mechanism, we must learn how browsers determine what style to apply when there are conflicts.

“Cascade” means resolving the conflict between the styles applied for a particular element when there are multiple CSS declarations for the element and a combination of multiple stylesheets.

In this article, we will see how conflicting style rules are applied using a concept called specificity.

If you have used CSS frameworks like bootstrap, you might have noticed that you are not able to easily add extra style to some elements like buttons. This is because of the CSS specificity. So you need to add a more “specific” selector to change the CSS of the button.

Take a look at the below code:

// HTML
<p class="para" id="para_id">This is a paragraph</p>
// CSS
p {color: red;}
#para_id {color: green;}.para {color: blue;}

What do you think, what will be the color of the paragraph? Are you confused?

Answer: The color will be green.

I know, It’s really confusing to predict it until you understand what CSS specificity is.

So Let’s dive into it.

The CSS that will be applied is decided by the specificity priorities which are standardized across all browsers. The list below is in increasing specificity priority order. This means that the style connected to the highest priority will be applied to the element.

1. !important rule has the highest priority
2. Inline styles are the second-highest priority
3. id is the third priority
4. classes, pseudo-classes and attributes are the fourth priority
5. Element and pseudo-elements are the fifth priority

So in the case of the above code, there is no !important or inline styles, so they are out of the game. However, there is an id, class, and element selector. So since id has the highest priority, it wins, and the color green will be the color of the paragraph.

You can play with the code here: https://codepen.io/myogeshchavan97/pen/WNbxqMO?editors=1100#0

Try removing id or class and see what happens.

Now, take a look at the below code

// HTML
<div id="list">
<p class="favorite" id="must-buy"><span>Butter</span></p>
</div>
// CSS
div#list #must-buy { color: red; }
.favorite span { color: blue !important; }

Can you identify the color of the text “Butter”?

Answer: It will be blue

Why? Because even though id has more priority than class, !important has top priority so it always wins.

Play with it here: https://codepen.io/myogeshchavan97/pen/VwYKZmX?editors=1100#0

Take a look at the below code:

// HTML
<div class="list">
<p class="favorite">
<span class="highlight">Butter</span>
</p>
</div>
// CSS
div.list p .highlight { color: red; }
div.list p .highlight:nth-of-type(odd) { color: black; }

It looks complicated, right?

Let’s simplify it.

We will write the count of how many times the selector is present.
So consider the first CSS rule

div.list p .highlight { color: red; }

1. !important: There is no !important so the count is 0
2. Inline styles: There are no inline styles so the count is 0
3. Id: There are no id’s so the count is 0
4. Classes, Pseudo classes and attributes: There are two classes here, .list and .highlight so the count is 2
5. Elements and pseudo-elements: There are 2 elements, div and p so the count is 2.

So if we write them in one line, it becomes

 0 0 0 2 2

Now consider, next CSS rule

div.list p .highlight:nth-of-type(odd) { color: black; }

1. !important: There is no !important so the count is 0
2. Inline styles: There are no inline styles so the count is 0
3. Id: There are no id’s so the count is 0
4. Classes, Pseudo classes and attributes: There are 2 classes .list and .highlight and 1 pseudo-class nth-of-type so the count is 3
5. Elements and pseudo elements: There are 2 elements div and p so the count is 2

So if we write them in one line, it becomes

 0 0 0 3 2

To identify which one gets applied, we need to compare each column value

0 0 0 2 2 -> div.list p .highlight { color: red; }
0 0 0 3 2 ->
div.list p .highlight:nth-of-type(odd) { color: black; }

First column is 0.
Second Column is 0.
Third Column is 0
Fourth Column is 2 for the first rule and 3 for the second rule so the second rule is the winner and the color is black.

Play with it here: https://codepen.io/myogeshchavan97/pen/KKwgPmp?editors=1100

So now you got the idea…

What will happen if all the columns have the same values as shown below:

0 0 0 2 2
0 0 0 2 2

In this case, the rule written last will take priority and that CSS will be applied. So if you import multiple stylesheets, the last one imported will have its styles applied when specificity is equal.

Key Points:

  1. !important has the highest priority and can’t be overwritten. This means we should not use this to apply styles because it’s hard to manage conflicts and debug CSS. It should be used only when there is no other option.
  2. Use id less often than class. id takes priority over classes so you will have to use it carefully to make sure you don’t create a style that is too specific to change if you share the component across your app.
  3. The best way to get resolve styling conflicts is to add more classes to make the specificity higher. This makes your CSS code more intentional and prevents you from running into a case where you have an element styled with id or !important that you’re unable to change.

Don’t forget to subscribe to get my weekly newsletter with amazing tips, tricks, and articles directly in your inbox here.

--

--