Selector Specificity
When developing complex web pages, CSS selector specificity is the deciding factor in determining whether styles ultimately take effect. When multiple rules target the same element and conflict with one another, browsers rely on a specific algorithm to decide which style applies. Mastering this mechanism not only helps developers troubleshoot "styles not working" issues but also results in clearer code structures and better maintainability.
The calculation of CSS selector specificity follows a strict set of mathematical rules. Its core lies in converting different types of selectors into numerical values for cumulative comparison. This algorithm does not consider the order in which rules appear in the CSS file (i.e., a rule defined later does not necessarily override an earlier one); rather, it depends entirely on the "specificity" of the selector itself. Understanding this mechanism is crucial for building robust frontend projects.
Basic Formula and Classification for Weight Calculation
According to the CSS3 specification, any complex selector can be decomposed into a combination of several basic types, each corresponding to a fixed weight value (0, 1, or 2). When comparing, browsers sequentially compare the total values of each category from lowest to highest: first by the count of ID selectors, then by the count of class and attribute selectors, and finally by the count of tag and pseudo-class selectors.
The specific classification standards are as follows:
- ID Selectors (e.g.,
#header) have the highest weight; each ID contributes 100 points; - Class, Attribute, and Pseudo-class Selectors (e.g.,
.btn,[type="text"],:hover) have a secondary weight; each such selector contributes 10 points; - Tag and Pseudo-element Selectors (e.g.,
div,::before) have the lowest weight; each contributes only 1 point.
It is worth noting that the priority of compound selectors is the cumulative sum of the weights of their parts. For example, a selector containing an ID, a class, and a tag has a total weight of $100 + 10 + 1 = 111$. This mechanism ensures that structures that are more specific (such as those referenced by ID) are harder to override by other rules; conversely, generic selectors are more easily interfered with by more specific ones.
Priority Comparison Analysis in Practical Cases
To intuitively demonstrate the weight differences among various selectors, we can derive and compare them through several typical scenarios. Assume we have a page containing a heading <h1 id="main-title"> and a button <button class="submit">.
Scenario 1: Single ID vs. Multiple Classes
If the following two rules exist:
/* Rule A */
#main-title { color: red; } /* Weight: 100 */
/* Rule B */
.submit, h1 { color: blue; } /* Weight: 2 (two classes/tags) + additional logic needs deconstruction; simplified here to compare core difference */
A more accurate comparison is actually #main-title (Weight 100) versus .submit (Weight 10). Obviously, as long as an ID selector exists, it can easily overwhelm all combinations of classes. This means that after defining a global red text style in the CSS file, any element with a specific ID will be forced to display as red unless covered by a higher-specificity rule.
Scenario 2: The Trap of Descendant Selectors
Many beginners tend to overestimate the power of "wildcards" or generic tag selectors. Consider the following code snippet:
/* Incorrect usage */
body div p { color: black; } /* Weight: 3 (1+2) */
/* Correct high-specificity usage */
#page-content .article-title { color: blue; } /* Weight: 101 (100 + 10 + 1) */
In the above example, the total weight of body div p is only 3, while #page-content .article-title reaches 101. Even if the latter is written at the end of the CSS file, the former still cannot take effect; conversely, if the high-weight rule is placed at the beginning of the file, it can override all low-specificity styles defined later. This reminds developers: do not rely on "writing last" to solve problems, but instead resolve conflicts by increasing selector specificity.
Best Practices and Code Standards Recommendations
Based on the aforementioned weight mechanism, the following principles should be followed during development to optimize CSS architecture:
- Prioritize using IDs for critical positioning: For unique and important elements in a page (such as the main navigation or footer), assign a unique ID to allow precise control via high-specificity rules.
- Avoid overly nested descendant selectors: Writeings like
div div p spannot only have low weight (prone to being overridden by subsets) but also suffer from poor code readability. It is recommended to use class names to combine semantic styling logic. - Adhere to the cautious principle of using
!important: Although adding!importantcan forcibly increase priority, this severely reduces CSS maintainability and debugging difficulty. It should only be used as a last resort when conflicts truly cannot be resolved through selector hierarchy (such as interference from third-party library styles).
In summary, CSS selector specificity is a systematic engineering approach based on mathematical logic. A deep understanding of the weight relationships between IDs, class names, and tags enables developers to manage style conflicts in complex page layouts with ease, writing code that is both aesthetically pleasing and rigorous.