In this article, I'll be explaining what CSS spe-ci-fi-ci-ty is and how it works in very simple terms.
Remember when you were watching that tutorial on CSS and you were told styles are applied from top to bottom, and that the styles that appear below would overwrite the one at the top....well that's not the full story.
CSS Specificity
CSS Specificity is the set of the rules applied to CSS selectors in order to determine which style is applied to an element. With proper understanding, you will understand why a style is not being applied to the element or why a particular style is applied even if there's a declaration below that overwrites it.
Let's look at this example:
.btn {
color: #fff;
background-color: blue;
}
.btn {
color: #fff;
background-color: red;
}
If we were to check this in our browser, our button would have a background color of red and a text color of white. That is fine, considering the styles that appear after would overwrite the one before. But what if we had something like this?
.btn.bg {
color: #fff;
background-color: red;
}
.btn {
color: #fff;
background-color: blue;
}
You'd expect the button to have a blue background, but in this case, the button would have a background color of red.
The reason for this behavior is, you guessed right.... CSS Specificity
How does it work?
CSS selectors have weights applied to them, and the more the weights, the higher the priority.
Styles
This refers to the inline styling applied to an element. e.g
<button style="background-color: red">Submit</button>
The specificity for this is (1, 0, 0, 0), and it has the highest weight. To override this, you would need to use the !important
flag in your CSS, but that's not really advisable.
ID
Using an id selector would give a specificity of (0, 1, 0, 0).
#btn {
background-color: red;
}
ID's have a higher priority compared to classes and tag names.
Classes, pseudo-classes and attributes
Class selectors like:
.btn {
background-color: red;
}
Pseudo-classes like
.btn:hover {
background-color: red;
}
and attribute selectors like
.btn[type=submit]{
background-color: red;
}
all have a specificity of (0, 0, 1, 0)
Tag Names
Selecting a element using it's tag name has the least specificity of (0, 0, 0, 1). Here's an example of tag name selectors.
button {
background-color: red;
}
Examples
1 - Assuming we have the following html
<ul class="nav">
<li class="nav-item">Home</li>
<li class="nav-item">About</li>
<li class="nav-item">Contact</li>
</ul>
And the CSS:
li {
color: red;
}
ul > li {
color: blue;
}
.nav-item {
color: green;
}
- The specificity of the first selector would (0, 0, 0, 1).
- The specificity of the second selector would be (0, 0, 0, 2), because we have two element selectors.
- The specificity of the last selector would be (0, 0, 1, 0). When you view this in your browser, the elements should have a green color. In this case, it does not matter which one comes first, the one with the highest specificity wins. Let's do another one😉
2 - Given this html structure
<ul id="nav">
<li class="nav-item">Home</li>
<li class="nav-item">About</li>
<li class="nav-item">Contact</li>
</ul>
#nav > .nav-item:hover {
color: pink;
}
#nav > li:hover {
color: brown;
}
li.nav-item:hover {
color: orange;
}
- The first selector has a specificity of (0, 1, 2, 0)
- The second selector has a specificity of (0, 1, 1, 1)
- The third selector has a specificity of (0, 0, 2, 1)
In this case, the color of the list item on hover would be pink, since the
#nav > .nav-item:hover
selector has the highest specificity.
3 - Take a look at this complex selector.
#container main .card img:hover {
transform: scale(1.1);
}
The specificity for this would be (0, 1, 2, 2). Let's break this down.
Selector | Specificity |
---|---|
#container | (0, 1, 0, 0) |
main | (0, 0, 0, 1) |
.card | (0, 0, 1, 0) |
img | (0, 0, 0, 1) |
:hover | (0, 0, 1, 0) |
Total | (0, 1, 2, 2) |
And that's it. With proper understanding of how CSS specificity works, you'll easily able to debug your CSS. Some code editors like VSCode gives you hint about the specificity of the selector. All you need to do is hover on the selector. Here's how it would look in my VSCode:
Useful Tips
- Avoid using ID's and inline styling as much as possible. To override these, you might have to use another ID, an inline style or the
!important
flag. - If two CSS selectors have the same specificity, the last one is considered
- Weights are considered before the number, so a specificity of (0, 1, 0, 0) has a higher precedence to (0, 0, 2, 2)