Selector Specificity and Matching Rules

In CSS development, when multiple style rules apply to the same element, the browser must decide which rule takes precedence based on a specific algorithm. This process is known as "selector priority" or "CSS Specificity." Mastering its core logic is essential for building robust and maintainable style sheets. Understanding the weight calculation mechanism not only helps resolve style conflicts but also empowers developers to make more precise predictions when writing code.

The priority of CSS selectors is not determined by the order of declaration, but rather by a hierarchical structure of selector types that undergoes quantitative calculation. This mechanism categorizes different selectors into three primary levels: ID selectors, class selectors, and element selectors (along with pseudo-classes). The weight of each level decreases sequentially; however, once the weight of a specific level is met, subsequent rules typically do not take effect.

Principles of Base Weight Allocation

The calculation of CSS Specificity follows strict mathematical logic, with contribution values for different selector types as follows:

  • ID Selectors: Have the highest priority, contributing a value of 100 per selector.
  • Class Selectors, Attribute Selectors, and Pseudo-class Selectors: Hold secondary priority, contributing a value of 10 per selector.
  • Element Selectors and Pseudo-element Selectors: Have the lowest priority, contributing a value of 1 per selector.

It is worth noting that tag selectors (such as div) and universal selectors (*) fall under the category of element selectors, carrying a weight of only 1. Additionally, while attribute selectors (such as [type="text"]) are powerful in functionality, their weight is still categorized within the class selector tier, amounting to 10 points.

To better understand this mechanism intuitively, consider a simple scenario: if a piece of code uses ID, class, and element selectors simultaneously to target the same div container, the ID selector will completely override the effects of the latter two. This means that when defining styles, the use of ID selectors should be exercised with great caution, as they act as a "veto."

Weight Accumulation Rules for Complex Selectors

In real-world projects, we rarely use a single type of selector in isolation; instead, we often combine multiple selectors to target specific elements. In such cases, the total priority is the sum of the weights of each part. For example, a selector composed of two IDs, three classes, and one element calculates its Specificity value as follows:

$$ (2 \times 100) + (3 \times 10) + (1 \times 1) = 231 $$

This accumulation mechanism implies that even if a subsequently added CSS rule uses a more complex combination, it will still fail to take effect if its total weight is lower than that of the preceding rule. Conversely, if the new rule has a higher weight, it can override the old one. This characteristic requires developers to plan the structure of selectors in advance when writing code to avoid unintentionally creating priority conflicts.

Special Considerations for Pseudo-classes and Attribute Selectors

When handling complex styling requirements, pseudo-classes (:hover, :first-child) and attribute selectors ([data-value]) are frequently used to enhance the targeting capability of selectors. According to standard specifications, the weight calculation for these selectors has unique characteristics:

  • Pseudo-classes: Whether structural or state pseudo-classes, their weight is counted as 10, equal to that of class selectors. For instance, the :hover portion in div:hover contributes 10 points.
  • Attribute Selectors: Regardless of how specific the attribute is (e.g., [data-type="premium"]), its overall weight is still considered to be 10 points.

This means that if a page simultaneously contains #header (weight 100) and .nav:hover (weight 10 + 1 = 11), the former will always take precedence. Similarly, if [class="active"] is used, it does not hold a higher priority than a standard .active, reminding us that we should not blindly assume attribute selectors possess stronger matching capabilities.

Practical Examples and Conflict Resolution Strategies

To verify the above theory, let us examine a concrete HTML and CSS code snippet:

<div id="main-content">
  <div class="card active">
    <h3>Title</h3>
  </div>
</div>

The corresponding CSS rules are as follows:

/* Rule A */
#main-content .card {
  color: red;
}

/* Rule B */
.card.active {
  color: blue;
}

/* Rule C */
h3 {
  color: green;
}

Based on priority calculation:

  1. Rule A: Contains one ID (100) and one class (10), totaling a weight of 110.
  2. Rule B: Contains two classes (10 + 10), totaling a weight of 20.
  3. Rule C: Contains only an element selector (1), totaling a weight of 1.

Ultimately, #main-content .card has the highest weight; therefore, color: red; will take effect. Even if the .active class is defined with greater specificity, it cannot override the influence of the ID selector. This result intuitively demonstrates why abusing ID selectors in CSS leads to difficult-to-debug style issues.

Best Practice Recommendations

Based on an understanding of the selector priority mechanism, the following principles are recommended during development:

  • Use ID Selectors Sparingly: Unless absolutely necessary (e.g., targeting a specific singleton component), avoid using ID selectors to prevent their high weight from interfering with other layout rules.
  • Reasonably Combine Classes and Elements: Refine styling logic by combining multiple class selectors, maintaining high flexibility while controlling the growth of weights.
  • Utilize BEM Naming Conventions: Adopt the Block (block), Element (element), Modifier (modifier) naming convention, which naturally forms a clear hierarchical structure, aiding in the unified management of style priorities during team collaboration.
  • Test and Verify: In large projects, use browser developer tools to inspect the actual applied style values and confirm that the calculation results match expectations, especially in scenarios involving multiple external libraries introducing styles.

Mastering selector priority and matching rules is a core capability for improving CSS writing quality. Only by deeply understanding this underlying logic can one write modern front-end code that is structurally clear and highly maintainable.