CSS Specificity: Universal Selector and Combinators

In CSS, understanding how browsers calculate selector specificity is essential for managing cascade conflicts and writing predictable styles. This guide explains the specificity values assigned to the universal selector (*) and combinators (+, >, ~, and the descendant space), detailing how they factor into specificity calculations and providing clear examples of their behavior in stylesheets.

The Specificity Value: (0, 0, 0)

Both the universal selector (*) and all CSS combinators carry a specificity weight of exactly zero (0, 0, 0 or (0, 0, 0, 0) when accounting for inline styles).

They add no weight to the selector chain. When a browser calculates which rule takes precedence, neither the universal selector nor any combinator will increase the specificity score of that rule.

The Universal Selector (*)

The universal selector matches any element of any type. Despite matching elements, it does not count as a type selector (which normally adds 0, 0, 1).

  • Weight: 0, 0, 0
  • Behavior: It will style every matched element, but any selector with a higher specificity (such as a single element selector, class, or ID) will override it.

Example:

/* Specificity: 0, 0, 0 */
* {
  color: black;
}

/* Specificity: 0, 0, 1 */
p {
  color: red;
}

In this example, paragraphs will be red because the element selector p (0, 0, 1) outweighs the universal selector * (0, 0, 0).

CSS Combinators

Combinators define the structural relationship between selectors rather than targeting elements themselves. Because they only define relationships, they contribute nothing to specificity.

The standard CSS combinators include:

  • Child combinator (>): Matches direct children.
  • Next-sibling combinator (+): Matches the immediate next sibling.
  • Subsequent-sibling combinator (~): Matches any following sibling.
  • Descendant combinator ( - whitespace): Matches any nested descendant.

None of these symbols add weight to the calculation. Only the selectors on either side of the combinator are counted.

Example:

/* Specificity: 0, 0, 2 (div + p) */
div > p {
  color: blue;
}

/* Specificity: 0, 0, 2 (div + p) */
div p {
  color: green;
}

/* Specificity: 0, 0, 2 (h2 + p) */
h2 + p {
  color: purple;
}

In div > p, the score is 0, 0, 2 because there are two type selectors (div and p). The > combinator contributes 0. The selector div p has the exact same specificity (0, 0, 2) because whitespace functions identically to > in terms of weight calculation.

Breakdown of Combined Examples

To see how these rules work together, consider the following combinations:

Selector Breakdown Total Specificity
* Universal (0, 0, 0) 0, 0, 0
*.warning Universal (0, 0, 0) + Class (0, 1, 0) 0, 1, 0
body > * Element (0, 0, 1) + Child (0) + Universal (0, 0, 0) 0, 0, 1
article > p Element (0, 0, 1) + Child (0) + Element (0, 0, 1) 0, 0, 2
header + nav > ul ~ p 4 Elements (0, 0, 4) + 3 Combinators (0) 0, 0, 4

Summary

When calculating CSS specificity:

  1. Ignore *. It only applies styles without adding weight.
  2. Ignore combinators (+, >, ~, and whitespace). They establish relationships between nodes but add zero weight.
  3. Count only the actual targets, classes, attributes, pseudo-classes, IDs, and element types surrounding the combinators.