CSS Specificity: How the Cascade Chooses the Winning Rule
CSS specificity is the part of the cascade that helps the browser decide which rule wins when multiple selectors match the same element. If your styles seem to be ignored, specificity is often the reason.
Quick answer: Specificity is a scoring system for CSS selectors. A more specific selector overrides a less specific one when both target the same element, unless !important or source order changes the outcome.
Difficulty: Beginner
You'll understand this better if you know: basic CSS selectors, how rules are written in a stylesheet, and the idea that one element can match more than one selector.
1. What Is CSS Specificity?
CSS specificity is a way for the browser to compare selectors and decide which declaration should apply. It is part of the cascade, which combines source order, origin, importance, and selector strength.
- Specificity is calculated from the selector, not from the property value.
- Selectors with more targeted parts usually have higher specificity.
- IDs outrank classes, classes outrank element selectors, and inline styles outrank normal stylesheet rules.
- If two rules have the same specificity, the one that appears later in the stylesheet usually wins.
This matters because CSS is often written by many people over time, and the browser needs a consistent way to resolve conflicts.
2. Why CSS Specificity Matters
Specificity explains many everyday styling problems: a button color that refuses to change, a layout rule that seems ignored, or a component style that overrides your page styles unexpectedly.
When you understand specificity, you can:
- Predict which rule will apply before refreshing the page.
- Write selectors that are easy to override later.
- Avoid unnecessary use of !important.
- Debug stylesheet conflicts faster in browser dev tools.
It also helps you design maintainable CSS. Overly specific selectors can make later edits painful, while too little structure can make rules collide too often.
3. Basic Syntax or Core Idea
Specificity is not something you write directly in CSS. It is calculated automatically from the selector.
Selector weight basics
A simple way to remember the ranking is:
- Element selectors like p, h1, or div have low specificity.
- Class selectors, attribute selectors, and pseudo-classes have medium specificity.
- ID selectors have high specificity.
- Inline styles have the highest normal specificity.
Here is a simple example showing competing rules:
p {
color: blue;
}
.note {
color: green;
}
#warning {
color: red;
}If an element is a paragraph with class note and ID warning, the browser will apply the ID rule because it is the most specific.
How the browser compares selectors
The browser counts different selector parts and compares them in order. A selector with an ID beats one with only classes, and a selector with classes beats one with only element names.
Note: Specificity is compared before source order. Source order only breaks ties when selectors have equal specificity.
4. Step-by-Step Examples
Example 1: Element selector versus class selector
This first example shows the most common beginner pattern: a class rule overrides a plain element rule.
p {
color: gray;
}
.highlight {
color: orange;
}A paragraph with class="highlight" will become orange, because class selectors outrank element selectors.
Example 2: Two classes with the same specificity
When two selectors have the same specificity, the later rule wins.
.button {
background: black;
}
.button.primary {
background: royalblue;
}If the element has both classes, the second selector wins because it is more specific: it contains two class selectors instead of one.
Example 3: ID selector versus multiple classes
An ID selector usually beats any number of class selectors, which is why IDs can be hard to override later.
.card.featured {
border: 2px solid green;
}
#promo {
border: 2px solid red;
}Even if the class selector looks more descriptive, the ID selector wins because IDs carry higher specificity.
Example 4: Same selector, later rule wins
Source order matters when selectors tie.
.message {
color: purple;
}
.message {
color: teal;
}The second rule wins because both selectors are identical, so the later declaration takes priority.
5. Practical Use Cases
Specificity shows up in almost every non-trivial stylesheet. Common real-world uses include:
- Overriding a base style for a special component state such as active, disabled, or error.
- Creating theme overrides that should win over default page styles.
- Understanding why a framework or component stylesheet is overriding your local rule.
- Writing predictable utility classes that are easy to override when necessary.
- Debugging why a nested selector is not changing the element you expected.
For example, a form field might use a general input rule, but a validation state class can override the border color without changing the HTML structure.
6. Common Mistakes
Mistake 1: Assuming the last rule always wins
Many beginners expect source order to decide everything, but specificity is checked first. A later rule can still lose if its selector is weaker.
Problem: This rule appears later, but it does not override the more specific selector above it.
#sidebar p {
color: navy;
}
p {
color: black;
}Fix: Make the later rule at least as specific, or reduce the specificity of the earlier rule.
#sidebar p {
color: navy;
}
.content p {
color: black;
}The corrected version works because the selector now matches the same general level of specificity and can compete properly.
Mistake 2: Overusing IDs in selectors
IDs are powerful, but they are difficult to override later and can make styles brittle. This is a common reason teams struggle to theme or extend components.
Problem: The ID rule is hard to override without adding even more specificity or using !important.
#header .nav a {
color: white;
}
.nav-link {
color: black;
}Fix: Prefer class-based selectors for reusable styling.
.header .nav-link {
color: white;
}
.nav-link {
color: black;
}The corrected version is easier to manage because classes are simpler to override and reuse.
Mistake 3: Using !important to fight specificity
!important changes the cascade rules and can make future debugging harder. It should usually be a last resort, not a normal fix for specificity problems.
Problem: This overrides styles now, but it can create a long-term maintenance problem and unexpected conflicts later.
.alert {
color: red !important;
}Fix: Increase selector clarity instead of forcing the property.
.page .alert {
color: red;
}The corrected version works because it relies on normal cascade behavior instead of forcing an exception.
7. Best Practices
Practice 1: Keep selectors as simple as possible
Short selectors are easier to understand and easier to override. A selector like .card .title is usually better than a deeply nested chain unless you truly need the extra precision.
.card .card-header h2 {
margin: 0;
}
.card-title {
margin: 0;
}The second approach keeps specificity lower and makes component styling easier to maintain.
Practice 2: Use classes for reusable styling
Classes are flexible because they can be applied to many elements and overridden without resorting to IDs or !important.
.button {
padding: 0.75rem 1rem;
}
.button.button--danger {
background: crimson;
}This approach gives you predictable, reusable styling with manageable specificity.
Practice 3: Let structure do the work, not extra selector weight
If you add extra descendants only to win conflicts, your stylesheet becomes fragile. Prefer meaningful class names over long selector chains.
.sidebar ul li a {
text-decoration: none;
}
.sidebar-link {
text-decoration: none;
}The second rule is easier to override later and easier to reuse in other layouts.
8. Limitations and Edge Cases
- !important can override normal specificity rules, so the usual ranking does not always decide the winner.
- Inline styles are very strong and often require more careful overrides than normal stylesheet rules.
- Specificity does not inherit from parents; each selector is judged on its own.
- Pseudo-classes like :hover, :focus, and :not() can affect specificity in ways beginners may not expect.
- Modern CSS features such as :is() and :where() have special specificity behavior, so they can be used to control how strong a selector feels.
- Browser dev tools may show a rule as crossed out, which usually means a more specific selector or later declaration won.
Note: If a style is “not working,” inspect the element in browser dev tools and compare the competing selectors. The crossed-out rule is often the weaker one, not a broken declaration.
9. Practical Mini Project
Let’s build a small notification card and use specificity to control the default style, the success state, and the urgent state.
<article class="notification notification--success">
<h2 class="notification__title">Backup complete</h2>
<p class="notification__text">Your files were saved successfully.</p>
</article>.notification {
padding: 1rem;
border: 1px solid #ccc;
background: #f8f8f8;
}
.notification__title {
margin: 0 0 0.5rem;
}
.notification--success {
border-color: #2e8b57;
background: #e9fff3;
}
.notification--success .notification__title {
color: #1f6b44;
}This project works because the base class sets the default card style, while the modifier class adds a stronger, targeted override for the successful state.
10. Key Points
- CSS specificity decides which matching selector wins.
- IDs are stronger than classes, and classes are stronger than element selectors.
- If specificity ties, source order decides the winner.
- !important overrides normal specificity and should be used sparingly.
- Simple selectors are easier to maintain than deeply nested ones.
11. Practice Exercise
- Write three CSS rules that target the same paragraph: one with an element selector, one with a class selector, and one with an ID selector.
- Predict which color will apply before testing it in the browser.
- Change the HTML so the paragraph matches all three selectors, then confirm your prediction.
Expected output: the paragraph should use the color from the ID selector, because it has the highest specificity among the three normal selectors.
Hint: Give the paragraph both a class and an ID so you can see the ranking clearly.
Solution:
<p id="message" class="alert">This paragraph demonstrates specificity.</p>p {
color: gray;
}
.alert {
color: orange;
}
#message {
color: darkred;
}The paragraph turns dark red because the ID selector outranks the class and element selectors.
12. Final Summary
CSS specificity is the rule-ranking system that helps the browser resolve conflicts between matching selectors. Once you understand how element selectors, class selectors, IDs, and source order interact, many “why isn’t my style applying?” problems become much easier to solve.
The key habit is to write selectors that are specific enough to express your intent, but not so specific that they become hard to override later. In most projects, class-based styling gives you the best balance of clarity, flexibility, and maintainability.
Next, practice reading selector conflicts in browser dev tools so you can spot specificity issues quickly in real stylesheets.