Understanding CSS Specificity: What It Is and How It Works
Mastering CSS Specificity: A Comprehensive Guide for Web Developers
When it comes to creating styles for web pages, Cascading Style Sheets (CSS) is the preferred tool of many developers. However, there is one aspect of CSS that can be a source of confusion: specificity.
Specifically, how does CSS determine which style rules will be applied when multiple rules apply to the same element? That’s where specificity comes into play.
What is CSS Specificity?
CSS Specificity refers to the set of rules that determines which CSS rule applies to an element on a web page. The specificity of a selector is measured by how detailed it is. In general, the more specific a rule is, the more weight it carries.
How CSS Specificity is Calculated
Specificity is calculated based on the number of elements, classes, IDs, and pseudo-classes that are contained within a rule. The specific order of how the values are defined is important, and it goes as follows:
Inline styles (
<style>
within an HTML tag)IDs (
#
)Classes, attributes, and pseudo-classes (
.
or:
)Elements and pseudo-elements (
div
,p
,::before
,::after
, etc.)
In terms of specificity, each category carries more weight than the one before it. For example, #id
is considered more specific than .class
, which is more specific than element
.
To determine the specificity of a particular rule, you add up the number of occurrences of each of these selectors in the rule. For example:
div .myclass p {
font-size: 24px;
}
This rule applies the font-size
property to all p
elements that are children of an element with class="myclass"
, which is in turn a descendant of a div
element. The CSS specificity of this example is:
Element selector:
1
Class selector:
1
Descendant combinator (space):
1
Total specificity:
1-1-1
The Four Levels of Specificity
There are four distinct levels of specificity in CSS:
The Universal Selector. This selector has a specificity of 0, meaning it has no impact on specificity calculations at all. It’s represented by an asterisk –
*
.Type Selectors and Pseudo-Elements. Type selectors apply to elements of a specific type, such as
div
,p
, ora
. They have a specificity of1
. Pseudo-elements::before
and::after
can also be included in this category because they aren't technically "selectors" but do affect specificity. They also have a specificity of1
.Class Selectors, Attribute Selectors, and Pseudo-Classes. Class selectors begin with a period (
.
), attribute selectors use brackets ([ ]
), and pseudo-classes are preceded by a colon (:
). They all have a specificity of10
.ID Selectors. IDs are selected using a hash (
#
), and they have the highest specificity level of100
.
To put this in perspective, consider the following CSS rules:
#menu a {...} /* specificity: 100 + 1 = 101 */
.main-nav a {...} /* specificity: 10 + 1 = 11 */
a {...} /* specificity: 1 */
Here, the #menu
selector has the highest specificity, at 101
. #menu a
is more specific than .main-nav a
, so its style rules will overrule the other. Meanwhile, a
applies to all elements, so its rules will be applied last.
Specificity and The Use of Combinators
One of the things that can make CSS specificity tricky is the use of combinators, which are used to combine or relate different elements in a selector. The main combinator types are:
Descendant combinator - represented by a space - which selects elements that are descendants of the first element.
Child combinator - represented by the greater-than symbol
>
- which selects only direct child elements of the first element.Adjacent sibling combinator - represented by a plus sign
+
- which selects the first sibling immediately following the first element.General sibling combinator - represented by a tilde
~
- which selects all siblings that follow the first element.
To put this in perspective, check out the following examples:
Descendant combinator - adds 0 points
body p { /* 0 points */ }
Child combinator
>
- adds 1 pointnav > ul { /* 1 point */ }
Adjacent sibling combinator
+
- adds 1 pointh2 + p { /* 1 point */ }
General sibling combinator
~
- adds 0 pointsh2 ~ p { /* 0 points */ }
It's important to note that combinators can add points to the specificity of a selector, but they do not affect the priority of selectors with higher specificity values.
CSS Specificity with Embedded and Inline Styles
CSS specificity can also vary depending on where the styles are defined, and how they are defined. For example:
Embedded Styles
<head>
<title>CSS Specificity Example</title>
<style>
h1 {
color: red; /* specificity: 1 */
}
#header h1 {
color: blue; /* specificity: 101 */
}
</style>
</head>
<body>
<div id="header">
<h1>CSS Specificity Example</h1>
</div>
</body>
Here we have two rules for h1
tags – one with a specificity of 1
, and one with a specificity of 101
. The #header h1
rule should be more specific and override the h1
rule, but both are defined in a stylesheet embedded within the head
section of the HTML document.
Inline Styles
<body>
<div id="header">
<h1 style="color: green;">CSS Specificity Example</h1>
</div>
</body>
In this example, the color of the h1
element is defined within an inline style. According to our specificity hierarchy, an inline style has a specificity of 1000
. Therefore, it would override any other conflicting styles by default.
Overriding CSS Specificity
There are several ways to override CSS specificity rules. Here are two common ones:
Using Important
p {
color: red !important; /* specificity: 1 */
}
.text-italic {
color: blue; /* specificity: 10 */
}
In this example, the color
of all p
elements will be red
because of the !important
keyword added to the rule.
Using Selectors
p#paragraph {
color: blue;
}
.text-italic p {
color: red;
}
Here, all paragraphs with id="paragraph"
will be blue, but all paragraphs that are descendants of elements with class text-italic
will be red.
Advanced Examples
As a general rule, selectors to the right have higher specificity than those to the left, so a.special
is more specific than .special
, but less specific than p#large.special
.
Here are some more examples that illustrate how CSS specificity works:
What is the color of the paragraph in each example?
Example 1/2
<p class="red">
I'm a red paragraph!
</p>
<style>
p.red {
color: red;
}
.red {
color: blue;
}
</style>
The paragraph element will have red text as the CSS selector .red
is more specific than the class selector p.red
. The p.red
selector has a specificity of 11
, as class selectors have ten points and the element selector has one.
Example 2/2
<div>
<p id="green">
I'm a green paragraph!
</p>
</div>
<style>
div #green {
color: green;
}
#green {
color: blue;
}
</style>
In this example, the paragraph element will have green text as the CSS selector div #green
is more specific than the ID selector #green
. The div #green
selector has a specificity of 12
, while the #green
selector has a specificity of 100
. Here, the specific selector div #green
wins over the less specific ID selector #green
.
Tips to Remember
Here are 3 tips to remember before start styling your page:
1️⃣ Inline style
attributes have a higher specificity value than any other type of selector.
<p id="my-id" class="my-class" style="color: red;">Inline styles win!</p>
In the example above, the color of the paragraph will be red, even though the ID selector has a higher specificity value.
2️⃣Pseudo-classes and pseudo-elements have their own specificity values.
.my-class:focus { /* 1 point */ }
.my-class::before { /* 1 point */ }
In the example above, both the :focus
pseudo-class and the ::before
pseudo-element have a specificity value of 1 point.
3️⃣ Specificity values can be calculated using the specificity
npm package or online calculators.
const getSpecificity = require('specificity');
const selectors = [ 'p', '.my-class', '#my-id', 'body p', 'nav > ul', 'h2 + p', 'h2 ~ p', '.my-class:focus', '.my-class::before'];
selectors.forEach(selector => {
console.log(getSpecificity(selector)[0].specificity);
});
In the example above, we can calculate the specificity values of each selector using the specificity
npm package.
By keeping these additional points in mind, you can gain a deeper understanding of how specificity works in CSS and how to use it effectively in your code.
Conclusion
CSS specificity can seem complicated at first, but it's an essential concept to master for any web developer. By understanding how specificity and combinator selectors work, you can ensure that your styles are consistently applied to HTML elements, without running into specificity conflicts or other issues that can cause your website to display incorrectly.
With the examples above, you can gain a better understanding of how specificity works in practice and how to apply it to your CSS stylesheets. Keep practicing and experimenting with CSS specificity, and you'll be a pro in no time!
Resources and References
MDN Web Docs: Specificity
CSS Tricks: Specifics on CSS Specificity
👋 Hello, I'm Eleftheria, devrel and content creator.
🥰 If you liked this article, consider sharing it.
🌈 All links | Twitter | LinkedIn | Book a meeting