CSS Specificity
Most times, CSS seems difficult to work with. You find out that styles you applied to a particular element don't take effect and you keep wondering why. This is as a result of CSS specificity.
Specificity is the means the web browser uses to determine the set of rules applied to a specific selector having two or more conflicting rules. The more weight a selector has, the higher the chance it stands to be applied.
In this article, I will explain what CSS specificity entails to help you make better decisions when styling web pages and avoid spaghetti code.
Hierarchy
Selectors have an order in which they have been placed in the specificity hierarchy which affects which one is considered a priority.
For single selectors from highest to lowest:
- Inline styles (
<nav style="color: #fff;">
) - IDs (
#myId
) - Classes (
.myclass
), attributes ([type="checkbox"]
) and pseudo-classes (:hover
) - Elements (
ul
) and pseudo-elements (::before
)
Rules of thumb
- By default, inline CSS is considered first before internal or external stylesheets.
!important
takes precedence over all declared styles.- Only use
!important
on page-specific CSS that overrides CSS from external libraries, e.g. Bootstrap, normalize.css etc. - To override
!important
that you have control over, rewrite the original rule to avoid the use of!important
. For scenarios where the previous declaration has a high specificity, give the selector a high specificity in your later declaration or the same specificity making the later take priority over the former.
[id="someElement"] p {
color: blue;
}
p.error {
color: red;
}
The styles above have the same specificity
- A more specific selector takes precedence over a less specific one
nav {
padding: 10px;
}
// The rule below has higher specificity
nav#main {
padding: 15px;
}
- Due to a cascading effect, rules that appear later in the code override earlier rules if both have the same specificity.
nav {
padding: 10px;
}
nav {
padding: 15px;
}
-
Universal selector (*), combinators (+, >, ~,), inherited values and negation pseudo-class (:not()) have no effect on specificity.
-
Styles targeted directly to an element will always take precedence over inherited styles, regardless of the specificity of the inherited rule.
<html>
<body id="parent">
<h1>Title</h1>
</body>
</html>
having the style below:
#parent {
color: blue;
}
h1 {
color: purple;
}
will have purple applied to it.
Calculating Specificity
A formula guides how CSS specificity is calculated. The selector with the most specific value is applied.
For each given selector, add 1 to the column it appears within the specificity table and sum up the value afterwards to derive the specificity of the selector.S | I | C | E |
---|---|---|---|
0 | 0 | 0 | 0 |
Legend:
[S]: Inline styles
[I]: ID selectors
[C]: Classes, attributes and pseudo-classes
[E]: Elements and pseudo-elements
Start at 0,
- 1000 for style attribute,
- 0100 for each ID,
- 0010 for each attribute, class or pseudo-class,
- 0001 for each element name or pseudo-element.
Use Cases
section #content .data a:hover {...}
Using the formula,
S | I | C | E |
---|---|---|---|
0 | 1 | 2 | 2 |
specificity = 0 1 2 2 |
---|
Given an unordered list of two items having conflicting rules,
<ul class="list">
<li class="item">1</li>
<li class="item">2</li>
</ul>
.item {
color: #e90b8d;
}
ul > li {
color: #fff;
}
To determine the more specific selector, calculate the specificity of each selector.
Selector 1 has one class:
.item {
color: #e90b8d;
}
S | I | C | E |
---|---|---|---|
0 | 0 | 1 | 0 |
specificity = 0 0 1 0 |
---|
Selector 2 has two elements
ul > li {
color: #fff;
}
S | I | C | E |
---|---|---|---|
0 | 0 | 0 | 2 |
specificity = 0 0 0 2 |
---|
Result:
From the above calculation, you can see that selector 1 has a higher specificity (10) than selector 2 with a value of 2. Therefore, the list items will be pink in color (#e90b8d).
Check out the visual representation of CSS specificity for more information.