Understanding CSS Specificity
CSS specificity is a numerical value that determines how specific a CSS selector is.
When multiple selectors target the same element, the rule with the higher specificity takes precedence.
This is one of the core principles that determines the priority of style rules in CSS
Specificity is calculated based on the types of selectors used—such as element selectors, class selectors, and ID selectors.
The more specific the selector, the higher its priority in the cascade.
Mastering this concept is essential for writing reliable, maintainable CSS in web development.
The Role and Importance of CSS Selectors
Understanding the basic concept of CSS selectors is essential for effective styling in web development. Selectors are used to target HTML elements on a page, allowing you to apply styles that control layout, design, and visual presentation.
Using the right selectors enables you to apply styles precisely to the intended elements. This not only improves code maintainability and reusability but also makes it easier to scale and manage styles across large projects.
Efficient use of selectors can streamline your styling process and contribute to better overall website performance.
What Is CSS Specificity?
When styling HTML elements with CSS, there are often cases where multiple rules with different selectors target the same element. So how does the browser decide which rule to apply?
Let’s walk through an example to understand how specificity determines which rule takes precedence.
<p id="my-id" class="a b">
This is a paragraph element.
</p>
* {
color: red;
}
p {
color: blue;
}
#my-id {
color: green;
}
.a {
color: olive;
}
.b {
color: pink;
}
<p>
element, the style from the #my-id
selector—setting the color to green—is the one that takes effect.
This is a paragraph element.
The example above demonstrates how styles are applied when multiple CSS selectors target the same element. Although several selectors are used, the style from the #my-id
selector is applied. But why does the #my-id
selector’s style take precedence?
The reason the style from the #id
selector is applied is that CSS follows a specific set of rules for determining which selector takes priority when multiple selectors target the same element. Let’s explore what these rules are.
Specificity is the key factor in determining which CSS selector is applied!
- The
id
attribute represents a unique value within a web document. Because it is unique, it is considered highly specific. Naturally, the#id
selector is regarded as a very specific way to target elements. - The
*
selector matches all elements on the page. Since it targets every element, it is considered non-specific. - The
.class
selector targets elements whoseclass
attribute matches the specified value. It is less specific than an#id
selector but more specific than the*
selector.
In CSS, when multiple selectors target the same element, the priority of which style rule is applied is determined by how specifically the selectors are defined. This priority rule is known as the CSS specificity value, or simply "specificity."
The specificity value is a numerical measure that determines the priority of style rules applied to elements.
It is calculated based on the combination of element types, classes, IDs, and other components within a selector. The higher the specificity value, the higher the priority. Specificity defines which style rule takes precedence when conflicts occur, allowing for more precise control over styling.
Rules for Calculating CSS Specificity Values
- The specificity value is expressed as four components, such as
0,0,0,0
, and is calculated as follows. - Each
#id
selector in the selector adds0,1,0,0
to the specificity value. - Each
.class
selector, pseudo-class selectors (like:first-child
,:last-child
,:focus
,:active
,:visited
,:hover
,::selection
, etc.), and attribute selectors add0,0,1,0
to the specificity value. - Each element name selector and pseudo-element selector (such as
::before
,::after
) adds0,0,0,1
to the specificity value. - The universal selector (
*
) does not contribute any value and has no effect on specificity. :is()
,:has()
, and:not()
themselves do not add to specificity. However, the selectors inside their arguments do affect specificity.:where()
does not add any specificity value, and selectors inside it also do not affect specificity.- The combinational or hierarchical structure of selectors does not affect specificity values.
CSS Specificity Examples
Let's calculate CSS specificity values using the rules we just covered through the following examples.
h2 {color: red;} /* Specificity = 0,0,0,1 */
p em {color: purple;} /* Specificity = 0,0,0,2 */
.grape {color: purple;} /* Specificity = 0,0,1,0 */
* .bright {color: yellow;} /* Specificity = 0,0,1,0 */
p.bright em.dark {color: maroon;} /* Specificity = 0,0,2,2 */
#id216 {color: blue;} /* Specificity = 0,1,0,0 */
p#addr [href] {color: gray;} /* Specificity = 0,1,1,1 */
Now, let's apply these specificity values to the example we reviewed earlier to better understand how specificity works.
<p id="my-id" class="a b">
This is a paragraph element.
</p>
* { /* Specificity = 0,0,0,0 */
color: red;
}
p { /* Specificity = 0,0,0,1 */
color: blue;
}
#my-id { /* Specificity = 0,1,0,0 */
color: green;
}
.a { /* Specificity = 0,0,1,0 */
color: olive;
}
.b { /* Specificity = 0,0,1,0 */
color: pink;
}
#my-id
— is applied, resulting in the text color being green.
This is a paragraph element.
Specificity of Inline Styles
So far, the specificity values we've discussed all start with a leading 0
. You might be wondering why this initial 0
exists. This leading number represents the specificity assigned to inline styles applied directly via the HTML element’s style
attribute.
Since inline styles are applied directly on the element itself—not through a selector—they naturally have the highest specificity.
<!-- Specificity = 1,0,0,0 -->
<h1 id="green-color" style="color:red;">This is a heading selected by an ID.</h1>
CSS Specificity Calculation Cheat Sheet
Selector Type | Specificity Value |
---|---|
Inline styles | 1,0,0,0 |
ID selector (#id ) |
0,1,0,0 |
Class, attribute, pseudo-class | 0,0,1,0 |
Element, pseudo-element | 0,0,0,1 |
Universal selector (* ) |
No effect |
:is() , :has() , :not() (outside) |
No effect |
Selectors inside :is() , :has() , :not() |
Counted normally |
:where() and selectors inside it |
No effect |
Combinators (e.g. > , + , space) |
No effect |
The !important
Declaration
Sometimes, certain CSS properties need to take precedence over others regardless of specificity. In such cases, the !important
declaration can be used to override the normal specificity rules and ensure that the style is applied first.
Let’s apply the !important
declaration to the example where we previously calculated specificity values.
<p id="my-id" class="a b">
This is a paragraph element.
</p>
* { /* Specificity = 0,0,0,0 */
color: red;
}
p { /* Specificity = 0,0,0,1 */
color: blue;
}
#my-id { /* Specificity = 0,1,0,0 */
color: green;
}
.a { /* Specificity = 0,0,1,0 */
color: olive !important; /* Overrides other styles using !important */
}
.b { /* Specificity = 0,0,1,0 */
color: pink;
}
!important
was applied, overriding the normal specificity rules.
This is a paragraph element.
Declarations marked with !important
don’t carry a special specificity value, but they are treated separately from normal declarations. In practice, specificity is compared among !important
declarations independently from regular declarations.
This means that when a conflict occurs between a normal declaration and one marked with !important
, the !important
declaration takes precedence—regardless of the usual specificity rules.
When Should You Use !important
?
- It's useful when you need to override inline styles.
- It’s especially helpful when JavaScript sets styles via the
style
attribute, which results in inline styles. In such cases, using!important
can prevent JavaScript from overriding your styles. - It can also help when you want to override a rule with higher specificity without modifying the original selector.
What Happens When Multiple Selectors with the Same Specificity Target the Same Element?
So far, we’ve explored how specificity affects which styles are applied when multiple CSS rules target the same element.
But what if multiple selectors have the same specificity and target the same element?
In that case, the rule that appears later in the stylesheet will take precedence. This is known as overriding.
Let’s look at an example to see how it works in practice.
<p class="a b">
This is a paragraph element.
</p>
.a { /* Specificity = 0,0,1,0 */
color: olive;
}
.b { /* Specificity = 0,0,1,0 */
color: pink;
}
This is a paragraph element.
This example shows that when multiple rules have the same specificity, the one defined later in the stylesheet takes effect.
When the Same Property Is Defined Multiple Times in the Same Selector
If the same CSS property is declared more than once within a single selector, the last defined value will be applied.
<p class="a b">
This is a paragraph element.
</p>
.a {
color: olive; /* The same property is declared more than once */
color: red; /* The last one will be applied */
}
red
, is applied because it was defined last within the selector.
This is a paragraph element.
When Multiple !important
Declarations Are Applied to the Same Element
<p class="a b">
This is a paragraph element.
</p>
.a { /* Specificity = 0,0,1,0 */
color: olive !important;
}
.b { /* Specificity = 0,0,1,0 */
color: blue !important;
}
!important
declarations have the same specificity, the one declared last will take precedence. In other words, it overrides the previous ones.
This is a paragraph element.
When multiple !important
declarations are present, as shown in the previous examples, if their specificity values are equal, the style declared last will be applied. The same rule also applies when the same property is declared multiple times within the same selector.
Common Pitfalls and Mistakes to Watch for with CSS Specificity
CSS specificity is crucial for understanding and managing style priorities, but it can also lead to common pitfalls and errors if not handled carefully.
#id
Selector's High Specificity: The#id
selector has a very high specificity value. Overusing#id
selectors can increase the likelihood of conflicts with other selectors. Since IDs are meant to be unique identifiers, it is best to reserve them for that purpose and use.class
selectors for styling whenever possible.- Low Specificity of the Universal Selector: The universal selector
*
has no specificity value. Excessive use of it can lead to specificity conflicts with other selectors. It's recommended to use more specific selectors when defining style rules. - Unnecessary Selector Nesting: Complex and deeply nested selector hierarchies increase specificity values. Unnecessary nesting can cause specificity conflicts and reduce the maintainability and readability of style rules. Use concise, direct selectors to keep specificity low and code easier to maintain.
- Priority of Inline Styles: Inline styles have the highest specificity of all selectors. Overusing inline styles can unintentionally override other style rules. It is best to minimize inline styles and instead define styles within CSS files to maintain consistency and ease of maintenance.
To avoid these pitfalls and mistakes, it is essential to understand the concept of specificity and use selectors appropriately when writing style rules. Proper comprehension and application of specificity values help prevent unexpected style conflicts and improve consistency and maintainability of web page styling.
Performance Considerations for Efficient Selector Usage
When using CSS selectors efficiently, it's important to consider performance. Here are some key tips to improve selector efficiency and performance:
- Keep specificity low: Using selectors with lower specificity generally offers performance benefits over highly specific selectors. Avoid excessive use of many elements,
.class
, or#id
selectors, as they increase selector complexity and matching overhead. - Use minimal selectors: Apply only the minimal selectors necessary to achieve the desired styling. Avoid unnecessary parent/child selectors and prefer direct selectors to define style rules, which helps improve performance.
- Limit usage of universal selector (
*
): The universal selector matches every element, making it potentially inefficient during matching. Whenever possible, use specific element selectors instead to reduce reliance on the universal selector. - Restrict selector scope: Narrow the scope of selectors to optimize the matching process. If styles only need to apply within a specific parent element, include that parent in the selector to limit scope.
- Reduce the number of style rules: Minimizing the total number of style rules applied on a page also helps performance. Remove unnecessary rules and keep the stylesheet as concise as possible to enhance efficiency.
Keeping these performance considerations in mind when writing selectors will help you style web pages more efficiently.
Specifications
Specification | |
---|---|
Calculating a selector’s specificity |
Selectors Level 4 #specificity-rules |