Skip to main content
Selector matching is the process of determining which CSS rules apply to each element in the DOM. This involves matching selectors, calculating specificity, resolving the cascade, and computing inherited styles.

Selector matching with specificity calculation

The selector matching algorithm determines whether a selector matches a given element and calculates the selector’s specificity for cascade resolution.

Matching algorithm

Selectors are matched from right to left for performance optimization:
1

Start with the rightmost selector

Begin matching with the rightmost simple selector (the “key selector”). This is the selector that directly matches the target element.For example, in div.container > p.highlight, start by checking if the element is a p with class highlight.
2

Check the key selector

If the key selector doesn’t match the element, immediately reject the entire selector. This early rejection is crucial for performance.Why right-to-left? Most selectors won’t match most elements. Starting from the right allows quick rejection without traversing the DOM tree.
3

Process combinators and remaining selectors

If the key selector matches, work leftward through combinators:
  • Descendant combinator ( ): Check ancestors
  • Child combinator (>): Check parent
  • Adjacent sibling combinator (+): Check previous sibling
  • General sibling combinator (~): Check all previous siblings
4

Validate the entire selector chain

Continue until the entire selector is validated or any part fails to match.
Right-to-left matching is counterintuitive but significantly faster than left-to-right. The key selector acts as a filter, eliminating most elements before expensive DOM traversal occurs.

Specificity calculation

When multiple rules match an element, specificity determines which declarations take precedence. Specificity is calculated as a three-part value: (a, b, c).
Specificity is often written as a three-digit number (e.g., 1-2-3) but it’s actually three separate counters. A selector with specificity (0, 1, 0) always beats (0, 0, 100).
Specificity consists of three counters:
  • a: Number of ID selectors
  • b: Number of class selectors, attribute selectors, and pseudo-classes
  • c: Number of type selectors and pseudo-elements
Inline styles have even higher specificity (1, 0, 0, 0), and !important overrides everything.
Count each type of selector:
To compare two specificities:
  1. Compare the a values. Higher wins.
  2. If a values are equal, compare b values. Higher wins.
  3. If b values are equal, compare c values. Higher wins.
  4. If all values are equal, the later rule (in source order) wins.
Examples:
  • (0, 1, 0) beats (0, 0, 100) — one class beats 100 type selectors
  • (1, 0, 0) beats (0, 100, 100) — one ID beats 100 classes and 100 types
  • (0, 2, 1) beats (0, 1, 5) — two classes beat one class, regardless of types
Don’t think of specificity as a decimal number (0-1-10 is not “eleven”). It’s three separate counters, so (0, 1, 0) always beats (0, 0, 1000).
Best practices for managing specificity:
  • Keep specificity low by avoiding IDs in CSS
  • Use classes instead of complex descendant selectors
  • Avoid !important except for utility classes
  • Use CSS methodologies (BEM, SMACSS) to maintain consistent specificity
  • Leverage :where() for zero-specificity selectors when needed

Cascade resolution

The cascade is the algorithm that combines declarations from different sources and resolves conflicts when multiple rules set the same property on an element.

Cascade algorithm steps

1

Filter declarations

Collect all declarations that apply to the element based on selector matching. Include declarations from:
  • User agent stylesheets (browser defaults)
  • User stylesheets
  • Author stylesheets (your CSS)
  • Inline styles
2

Sort by origin and importance

Declarations are sorted by origin in this order (highest priority first):
  1. Transition declarations
  2. Important user agent declarations (!important in browser defaults)
  3. Important user declarations
  4. Important author declarations
  5. Animation declarations
  6. Normal author declarations
  7. Normal user declarations
  8. Normal user agent declarations
3

Sort by specificity

Within the same origin and importance level, declarations are sorted by selector specificity. Higher specificity wins.
4

Sort by source order

If origin, importance, and specificity are all equal, the declaration that appears later in the source code wins.
5

Apply winning declarations

For each property, the declaration that wins the cascade is applied to the element.
The cascade is why CSS is called “Cascading” Style Sheets. Multiple stylesheets cascade together, with conflicts resolved according to the cascade algorithm.

Important cascade behaviors

Normal declarations follow the order: user agent → user → author.Important declarations reverse this: author !important → user !important → user agent !important.This means a user’s !important declaration beats an author’s !important declaration, allowing users to override site styles for accessibility.
CSS transitions have the highest priority (they temporarily override even !important).CSS animations sit between !important declarations and normal declarations.This allows smooth transitions even when styles change dynamically.
Inline styles (e.g., <div style="color: red">) are treated as having specificity (1, 0, 0, 0), higher than any selector-based rule.Only !important declarations can override inline styles.

Inheritance

Some CSS properties are inherited by default, meaning child elements automatically receive values from their parent unless explicitly overridden.

Inherited vs. non-inherited properties

These properties automatically cascade to descendants:Typography:
  • color
  • font-family
  • font-size
  • font-weight
  • font-style
  • line-height
  • letter-spacing
  • text-align
  • text-indent
  • text-transform
  • white-space
Lists:
  • list-style
  • list-style-type
  • list-style-position
Other:
  • visibility
  • cursor
  • quotes

Inheritance implementation

Inheritance performance tip: When computing styles for many elements, compute parent styles first. This allows efficient inheritance without re-computing parent values for each child.
You now have a complete understanding of CSS selector matching, specificity calculation, cascade resolution, and style inheritance. These mechanisms work together to determine the final computed styles for each element in the document.