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.

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:

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:

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:

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

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

11. Practice Exercise

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.