Table of Contents
INTRODUCTION
CSS specificity is a scoring system that browsers use to determine which CSS rule should be applied when multiple rules could affect the same element. Think of it as a weight or priority system where more specific selectors override less specific ones.
When the browser encounters conflicting CSS rules, it doesn't just apply the last one it reads. Instead, it calculates the specificity of each rule and applies the one with the highest specificity score.
The Specificity Hierarchy
CSS specificity follows a four-category hierarchy, often represented as four numbers: a, b, c, d where:
- a = Inline styles → counts as 1 if present, otherwise 0
- b = Number of ID selectors
- c = Number of class selectors, attributes, and pseudo-classes
- d = Number of element selectors and pseudo-elements
1. Inline Styles (a = 1)
Inline styles have the highest specificity value of 1-0-0-0. These are styles applied directly to an element using the style attribute.
2. IDs (b = 1)
ID selectors have a specificity value of 0-1-0-0. Each ID selector adds 0-1-0-0 to the specificity score.
3. Classes, Attributes, and Pseudo-classes (c = 1)
This category includes class selectors, attribute selectors, and pseudo-classes, each contributing 0-0-1-0 to the specificity score.
4. Elements and Pseudo-elements (d = 1)
Element selectors and pseudo-elements have the lowest specificity value of 0-0-0-1.
5. The !important Declaration
The !important declaration overrides normal specificity calculations. It gives a rule the highest priority, regardless of specificity.
6. Universal Selector and Combinators
The universal selector (*), combinators (+, ~, >), and negation pseudo-class (:not()) don't add to specificity.
7. Inherited Styles
Inherited styles have no specificity. Any directly targeted rule, regardless of how low its specificity, will override inherited styles.
Examples
Example 1
h1 {color: blue; }
- No inline styles → a = 0
- No ID → b = 0
- No class/attribute/pseudo-class → c = 0
- One element → d = 1
Example 2
.card .title {
font-size: 18px;
}
- No inline → a = 0
- No ID → b = 0
- Two classes → .card and .title → c = 2
- No element → d = 0
Example 3
#main-nav a { color: teal; }
- No inline → a = 0
- one ID → #main-nav → b = 1
- No classes → c = 0
- one element → anchor → d = 1
Example 4
nav ul li a { color: brown; }
- No inline styles → a = 0
- No ID → b = 0
- No class/attribute/pseudo-class → c = 0
- Four element → d = 4
!important
The !important declaration is a special rule in CSS used to give higher priority to a specific CSS property. When a style is marked with !important, it overrides all other conflicting rules, even those with higher specificity, unless another rule also has !important.
Syntax
selector {
property: value !important;
}
Example - This ensures that all paragraph elements will have red text, even if there are other rules trying to set the color to something else.
p {
color: red !important;
}
What If Two Rules Have !important?
When two CSS rules both use !important, the browser will still need to decide which one wins. In this case, the normal specificity rules and source order are used to resolve the conflict. Let’s break it down:
- Compare specificity - The rule with the higher specificity takes precedence.
- If specificity is equal, check source order - The rule that appears later in the stylesheet or in a stylesheet that is included later will win.
Example - The color will be blue, because #header has higher specificity than .main-title.
<style>
#header {
color: blue !important; /* Specificity: 0,1,0,0 */
}
.main-title {
color: red !important; /* Specificity: 0,0,1,0 */
}
</style>
<h1 id="header" class="main-title">Hello!</h1>
!important impact on cascade origin order
The !important rule in CSS alters the normal cascade order, especially in the context of origin order. Here's a detailed explanation of how it affects the cascade origin hierarchy:
CSS Cascade Origins (from lowest to highest priority):
- User Agent Styles (browser defaults)
- User Styles (set by the user in browser settings)
- Author Styles (your CSS)
- Author Styles with !important
- User Styles with !important
- User Agent Styles with !important (rarely relevant)
Origin | Without !important Priority |
With !important Priority |
---|---|---|
User Agent Styles | 1 (lowest) | 6 (highest) (rare) |
User Styles | 2 | 5 |
Author Styles | 3 | 4 |
!important impact on Cascade Layers
In normal styles (without !important), the browser follows the order in which layers are created. The first layer written has the lowest priority, and the last one has the highest. Any styles that are not inside a layer come after all the layered styles.
But for styles marked with !important, the order is flipped. All !important styles that are not inside a layer are grouped together in a hidden layer. This group is stronger than all normal styles, but weaker than any !important styles inside layers.
Among !important layered styles, the ones in layers declared earlier have higher priority than those in layers declared later.
Frequently Asked Questions (FAQ)
What is the difference between specificity and the cascade in CSS?
1. Specificity
Specificity is a score (or weight) calculated based on the type of CSS selectors used. It helps the browser decide which rule takes precedence when multiple rules target the same element.
2. Cascade
The cascade is the overall algorithm CSS uses to resolve conflicts between multiple rules that apply to the same element. It takes multiple factors into account in a particular order: Cascade decision hierarchy:
- Origin and importance
- User-agent styles (browser default)
- User styles
- Author styles (your CSS)
- !important rules override others (but are still affected by specificity and layer order)
- Specificity (as explained above)
- Source order – If rules have equal specificity, the one that comes last in the CSS file wins.
Does !important override specificity?
1. A CSS declaration with !important will override other declarations even if they have higher specificity.
2. If two rules both use !important, then specificity matters again.
#box {
color: blue !important;
} /* Specificity: 100, important */
p {
color: red !important;
} /* Specificity: 1, important */
Now, color: blue will apply because both are !important, so the more specific selector wins.
Case | Winner |
---|---|
!important vs. normal rule |
!important wins |
!important vs. higher specificity |
!important still wins |
!important vs. !important |
Rule with higher specificity wins |
Equal !important and specificity |
Rule declared later in source wins |
What is the order of precedence in CSS selectors?
Represents | Specificity Value | Example |
---|---|---|
Inline styles | (1, 0, 0, 0) | style="color: red" |
ID selectors | (0, 1, 0, 0) | #main , #header |
Classes, attributes, pseudo-classes | (0, 0, 1, 0) | .btn , [type="text"] , :hover
|
Elements and pseudo-elements | (0, 0, 0, 1) | div , h1 , ::before |
How to increase CSS specificity?
Action | Effect on Specificity | Example |
---|---|---|
Add ID selector | Increases by 100 | #header .btn |
Add class/attribute/pseudo-class | Increases by 10 | .btn.primary:hover |
Add element selector | Increases by 1 | h1 strong |
Use inline style | Increases to 1000 | style="color:red" |
Use !important |
Overrides all (not specificity-based) | color: red !important |
Use :where() |
No specificity added | :where(.low) |
How to decrease CSS specificity?
Method | Description | Example |
---|---|---|
Use fewer selectors | Simplify the selector chain | h1 instead of #header h1 |
Remove ID selectors | IDs have very high specificity | Use .header instead of #header |
Use class instead of inline style | Avoid style="" unless absolutely necessary |
Use .text-red in CSS |
Use cascade layers | Place lower-priority styles in earlier layers | @layer base { ... } |
Use :where() pseudo-class |
Zero-specificity wrapper that doesn't affect specificity | :where(.low-priority) |
How can I override CSS specificity?
- Use !important - Forces a rule to win regardless of specificity.
- Use a more specific selector - Make your selector more specific than the one you're trying to override.
- Match the same specificity and place the rule later - CSS honors the rule that comes later in source order when specificity is equal.
- Use :where() to lower specificity - :where() adds zero specificity, so it’s easily overridden.
- Move the rule to a higher cascade layer - If using cascade layers (@layer), unlayered or later-layer rules can override earlier ones, regardless of specificity.
- Use inline styles - Inline styles have a very high specificity (1,0,0,0).
- Use ID selectors (if really necessary) They have higher specificity than classes and elements.