Cascade and Specificity

What You'll Learn

  • How the CSS cascade determines which styles apply
  • How to calculate specificity for any selector
  • Why one ID beats any number of classes
  • When source order matters and when it doesn't
  • How inline styles and !important fit into the cascade
  • Best practices for writing maintainable, predictable CSS

Introduction to the Cascade

The "Cascade" in CSS is the algorithm that determines which styles ultimately apply to an element when multiple rules compete. It's one of the most important—and often misunderstood—features of CSS.

Understanding the cascade helps you write CSS that behaves predictably. You'll know exactly why one rule overrides another, and you'll be able to structure your stylesheets to avoid specificity battles and the dreaded !important hack.

What is the Cascade?

When multiple CSS rules could apply to the same element, the cascade determines the winner using a specific order of priority:

  1. Origin and Importance - Where the CSS comes from:
    • Browser default styles (user agent)
    • User preferences
    • Author styles (your CSS)
    • !important declarations (reverse order)
  2. Specificity - How specific the selector is (if same origin)
  3. Source Order - Position in the stylesheet (if same specificity)

Understanding Specificity

Specificity is calculated as three numbers: (a, b, c). Each part counts different types of selectors. Think of it like a three-digit number where the leftmost digit has the most weight.

The Specificity Formula

  • a = Count of ID selectors
  • b = Count of class selectors, attribute selectors, and pseudo-classes
  • c = Count of element selectors and pseudo-elements

Quick Reference Table

/* Specificity Examples */ p /* (0, 0, 1) - 1 element */ .button /* (0, 1, 0) - 1 class */ #header /* (1, 0, 0) - 1 ID */ div p /* (0, 0, 2) - 2 elements */ .nav .item /* (0, 2, 0) - 2 classes */ ul li:first-child /* (0, 1, 2) - 1 pseudo-class, 2 elements */ #main .content p /* (1, 1, 1) - 1 ID, 1 class, 1 element */ button[type="submit"]/* (0, 1, 1) - 1 attribute, 1 element */ .btn.primary.large /* (0, 3, 0) - 3 classes */

Interactive Specificity Calculator

This demo shows how specificity is calculated for various selectors and how they compare to each other:

Specificity in Action

Let's see a practical demonstration of how different specificity levels compete for control of an element's styling. Watch how higher specificity always wins:

/* Element selector - (0, 0, 1) */ p { color: gray; } /* Class selector - (0, 1, 0) - WINS over element */ .styled { color: blue; } /* ID selector - (1, 0, 0) - WINS over class */ #special { color: green; } /* Two classes - (0, 2, 0) - WINS over one class */ .styled.important { color: red; } /* Descendant combinator - (0, 1, 1) */ div.container p { color: purple; }

Notice how the element with class="styled" and id="special" is styled by the ID rule because (1, 0, 0) beats (0, 1, 0). This is why using IDs for styling can make your CSS hard to override.

Source Order

When two selectors have exactly the same specificity, the one that appears last in the CSS wins. This is called "source order."

/* Both have specificity (0, 1, 0) */ .box { color: blue; background: lightblue; } .box { color: red; /* This wins */ background: pink; /* This wins */ }

Inline Styles

Inline styles (using the style attribute) have higher specificity than any CSS selector. They're effectively calculated as (1, 0, 0, 0)—an extra digit that beats everything.

<!-- Inline styles beat all CSS selectors --> <div id="styled-box" style="color: red;"> This will be red, even if #styled-box { color: blue } </div>

The !important Declaration

Adding !important to a declaration gives it the highest priority, overriding even inline styles (unless the inline style also uses !important).

/* Low specificity, but !important makes it win */ .override { color: orange !important; } /* High specificity, but loses to !important */ #high-specificity { color: blue; }

Comparing Specificity Values

To compare specificity, read from left to right. The first number that differs determines the winner:

Examples

  • (1, 0, 0) beats (0, 10, 0)
    One ID beats ten classes
  • (0, 2, 1) beats (0, 1, 10)
    Two classes beat one class (the element count doesn't matter)
  • (0, 1, 1) beats (0, 1, 0)
    When first two numbers tie, check the third

Best Practices

Understanding specificity helps you write maintainable CSS. Here are key strategies to keep your stylesheets predictable and manageable:

Keep Specificity Low

  • Favor classes over IDs for styling
  • Avoid long descendant chains like .nav ul li a span
  • Use single class names when possible: .button instead of div.container .button
  • Reserve high specificity for truly exceptional cases

Keep Specificity Consistent

  • If most rules use (0, 1, 0), don't suddenly use (1, 0, 0)
  • Inconsistent specificity makes overriding styles unpredictable
  • Consider using a naming methodology like BEM to maintain consistency
  • Document any intentionally high-specificity rules

Use IDs for Functionality

  • Reserve IDs for JavaScript hooks and fragment identifiers
  • Style with classes, which are reusable and have lower specificity
  • This separation makes both your CSS and JavaScript easier to maintain

Avoid !important

  • Only use it for utility classes that must always apply
  • If you need it often, refactor your CSS structure
  • It makes debugging extremely difficult
  • Once you start using it, it tends to spread throughout your codebase

Key Takeaways