Decoding CSS Specificity: Navigating the Depths of Style Prioritization

Decoding CSS Specificity: Navigating the Depths of Style Prioritization

CSS specificity is the backbone of styling in web development, serving as the guiding principle for browsers to determine which CSS declarations take precedence when multiple style rules vie for control over a single HTML element. It operates as an algorithm, assigning a weight to CSS selectors and establishing a hierarchy that dictates the application of styles.

Visual definition of CSS terms

Specificity Hierarchy

Every CSS selector has its place in the specificity hierarchy.

There are four categories which define the specificity level of a selector:

  1. Inline styles - Example: <h1 style="color: pink;">

  2. IDs - Example: #navbar

  3. Classes, pseudo-classes, attribute selectors - Example: .test, :hover, [href]

  4. Elements and pseudo-elements - Example: h1, ::before

Thе Thrее-Column Valuе Spеcificity Algorithm:

The specificity algorithm revolves around a three-column compound number representing the three primary types of CSS selectors: ID, CLASS, and TYPE. Each column contributes to the specificity weight. This three-column compound number starts off with zeroes looking like [0,0,0] such that [ID,CLASS,TYPE]:

  1. ID Column:

    • Each ID selector adds [1, 0, 0] to the weight value.
  2. CLASS Column:

    • Class selectors, attribute selectors, and pseudo-classes contribute [0, 1, 0] to the weight value.
  3. TYPE Column:

    • Type selectors and pseudo-elements contribute [0, 0, 1] to the weight value.

Specificity Comparison with Examples:

Let's analyze two rules targeting a Div element in an example:

Rule1:

#container .section .content div {
    /* Declarations here */
}
  • ID selectors: [1, 0, 0]

  • Class selectors: [0, 2, 0]

  • Type selectors: [0, 0, 1]

Now provided the number in each column is 9 or less, we can concatenate the numbers in each column to get a base10 number as the resultant specificity weight. Resulting in a specificity weight of 121.

Rule2:

.article .content div {
    /* styles here */
}
  • ID selectors: [0, 0, 0]

  • Class selectors: [0, 2, 0]

  • Type selectors: [0, 0, 1]

Now provided the number in each column is 9 or less, we can concatenate the numbers in each column to get a base10 number as the resultant specificity weight. Resulting in a specificity weight of 021.

Because 121 is greater than 021, the former has precedence over the latter. Therefore, the former style rule will be processed to style the Div element.

Selectors with No Weight:

  • The universal selector (*) and the pseudo-class :where() have a weight of [0, 0, 0].

  • Combinators, such as +, >, ~, " ", and ||, don't contribute to specificity weight.

  • :not(), :has(), and :is() pseudo-classes add no weight by themselves, but their parameters impact weight in specificity calculation.

Example:

Consider the following HTML:

<html>
    <head>
        ...
    </head>
    <body>
        <div id="main-container" class="blog-post">
            <p>This is a blog post.</p>
        </div>
    </body>
</html>

Three CSS rules target the <p> element within the main container:

#main-container p {
    color: blue; /* [1, 0, 1] */
}

.blog-post p {
    color: green; /* [0, 1, 1] */
}

div p {
    color: red; /* [0, 0, 2] */
}

All the three rules have selectors matching the same and only <p> element in the HTML. The color will be blue because first rule has the highest specificity weight, i.e 101 is the greatest number from the weights of 101, 011 and 002.

Handling High Specificity Values:

When dealing with column numbers greater than 9, such as [15,8,21], we need to convert these values to a higher base to calculate the specificity weight. Let's choose a base number larger than 21, say 30, and follow the steps:

  1. Selecting a Base Number:

    • Choose a base number larger than the largest column number. In this case, let's choose a base of 30.
  2. Multiplying Columns:

    • Starting from the rightmost column, multiply each column value by powers of 30, working towards the leftmost column.
  3. Adding Results:

    • Sum up the results obtained from each column multiplication to get the total specificity weight.
(30) * 15       =      450
(30*30) * 8     =    7 200
(30*30*30) * 21 = 5 67 000
-------------------------
Total in decimal = 5 74 650

When we do this will also require to use that base number to calculate specificity weight for the other competing selectors.

All thanks to CSS processor handles all this for us. So we just have to understand "why a certain style has been applied and not the other".

Equivalent Weights:

When two or more rules have equivalent specificity weights, the most recent rule takes precedence. To override this, use the !important keyword. For instance:

div {
    color:     #008080 !important; /* [0, 0, 1] */
}

div {
    color:     #000080; /* [0, 0, 1] */
}

Both rules have the same weight but the first rule will take precedence because of use of !important keyword. Otherwise, the second rule would have taken precedence.

Also Whenever inline styles is applied, it has the highest specificity overriding any style in the style sheet. The only way to override an inline style from a style sheet is to use !important keyword.

Conclusion

Understanding CSS specificity is crucial for web developers to effectively control the styling of HTML elements. The specificity hierarchy, consisting of inline styles, IDs, classes, pseudo-classes, attribute selectors, elements, and pseudo-elements, provides a structured approach to resolving conflicts between competing style rules.

The three-column specificity algorithm, with its ID, class, and type columns, assigns weights to selectors and establishes a clear order of precedence. Concatenating these weights forms a specificity value, guiding browsers in determining which style rule to apply when conflicts arise.