How Does CSS Cascading & Specificity Algorithm Works Under The Hood?

Vinay BhardwajVinay Bhardwaj
6 min read

Introduction

In this article we will first understand about the CSS and how it’s used, and then dive into the working of Specificity Algorithm in CSS.

What is CSS?

CSS, which stands for Cascading Style Sheets, is a stylesheet language used to describe how a document will be presented to the user.

What is Cascade?

The Cascade is an algorithm that defines how User Agents (Browsers) combine property values originating from different sources. The cascade lies at the core of CSS, as emphasized by the name Cascading Style Sheets. It’s role is to select the CSS declarations in order to determine the correct values for CSS properties.

What are User Agent Stylesheets?

User Agents, or Browsers, have their own basic stylesheets that give the default styles to any document. And these stylesheets are nothing but User Agent Style Sheets. Each browser has their own default stylesheet, and some differences exists in them.

To resolve this problem, web developers use a CSS reset stylesheet, such as Normalized CSS, which sets some known state for all the browsers before beginning to make alterations based on specific needs.

What are Author Stylesheets?

Author Stylesheets are the styles written by web developers, used to define the styles for the document using one or more linked or imported stylesheets, <style> blocks, and inline styles defined with the style attribute. These styles define the look and feel of the website i.e., it’s theme.

What are User Stylesheets?

User Stylesheets are the custom styles added by the developer to override the User Agent Styles in the website to tailor the experience to the user’s wishes.

What is Cascading Algorithm?

It’s a method used to resolve conflicts when multiple CSS rules apply to the same HTML Element. It determines the style based on precedence by considering the order of rules, their specificity, and their origin. Basically cascading the styles down to the element being styled.

Steps involved in Cascading Algorithm

  1. Relevance - Filters all the rules from different sources to keep only the rules that apply to a given element.

  2. Origin and Importance - It then sorts these filtered rules according to their importance (i.e., whether or not they are followed by !important), and by their origin (i.e., User Agent or Author or User).

  3. Specificity - In case the origin is same, the specificity of a rule id considered to choose from the multiple values. The CSS declaration with the highest specificity wins over the other declarations.

  4. Scoping Proximity - When the two selectors with same origin and same level of specificity are present, then the property value within scoped rules having the smallest number of hops up the DOM hierarchy to the scope root wins.

  5. Order of Appearance - If even the scoping proximity is also equal for multiple declarations, then the last declaration in the style order is applied.

The cascade is in ascending order, and follow the below precedence whether declared in user, author, or user-agent styles:

  • Animations take precedence over Normal values

  • Important values take precedence over Animations

  • Transitions take precedence over Important values

What is CSS Specificity?

CSS Specificity is an algorithm used by browsers to determine which CSS declaration is more relevant to an element, which in turn, determines what property value to apply to an element. It calculates the weight of the CSS Selectors to determines which rule gets applied to an element.

How is Specificity Weight calculated?

The weight is calculated by the number of selectors of each weight category in the selector matching the element or pseudo-element.

The specificity algorithm is basically a 3-column value of 3 weight categories, mainly categorized as ID, CLASS & TYPE. The value represents the count of selectors in each weight and written in the format ID-CLASS-TYPE.

Specificity Selector Weight Categories and Other Exceptions

As mentioned above also, the weights are categorized as three-column viz., ID, CLASS & TYPE. We will see other exceptions and selectors which are not affected by specificity or override other declarations.

ID Column

It includes only ID selectors, such as #myId.

Let’s understand with the help of few examples:

#example {
    // ...
}

The weight value of above selector will be 1-0-0.

#examples #pratical {
    // ...
}

The weight value of above selector will be 2-0-0.

CLASS Column

It includes the following:

  • class selectors such as .my-class

  • attribute selectors like [type=”checkbox”]

  • pseudo-classes such as :hover, :nth-of-type(2n+1), :first-child

Let’s understand with the help of few examples:

.my-class {
    // ...
}

The weight value of above selector will be 0-1-0.

.links[href="#"] {
    // ...
}

The weight value of above selector will be 0-2-0.

#customButton:hover {
    // ...
}

The weight value of above selector will be 1-1-0.

TYPE Column

It includes the following:

  • type selectors such as p, div, h2

  • pseudo-elements such as ::before, ::after, ::placeholder

Let’s understand with the help of few examples:

span {
    // ...
}

The weight value of above selector will be 0-0-1.

span:hover {
    // ...
}

The weight value of above selector will be 0-1-1.

input::placeholder {
    // ...
}

The weight value of above selector will be 0-0-2.

:root #myID .my-class input:required {
    // ...
}

The weight value of above selector will be 1-3-1.

No Value

There are few selectors which don’t have any weight and hence, doesn’t add any value to the 3-column specificity weight. It includes the following:

  • universal selector, that is *

  • pseudo-classes, such as :where(), :is(), :has(), :not()

  • combinators, such as +, >, ~, “ “, ||, &

Inline Styles

Inline styles are added to the element directly using the style attribute. For example,

<h3 style="color: gray"> Heading 3 </h3>

These styles overrides any normal styles in author stylesheets, and hence have the highest specificity. The only way to override even inline style is by using !important.

The !important exception

CSS declarations marked as important override any other declarations within the same cascade layer or origin. If declarations from the same origin or cascade layer have conflicts and one of them is marked important using !important flag, then this declaration is applied to the selector no matter what.

It is recommended to not use !important as it’s considered as a bad practice and must be avoided wherever possible.

p.my-class {
  color: crimson !important;
}

The @scope blocks

Including a ruleset inside a @scope block doesn’t affect the specificity at all. However, if we use pseudo-class :scope explicitly, then it affects the calculations of specificity.

Equivalent Weights

When there are 2 or more declarations having the same specificity weight, then the most recent declaration will take precedence over others. Also, if any of them is marked important, then that will have most precedence.

Summary

We started with the basic of CSS, what is it, and then understood how CSS algorithms such as Cascade and Specificity works under the hood to make our life better. There might be more things to know regarding this topic and I hope we keep learning and exploring more things.

Thank you for reading this article till the end and please provide your valuable feedback as well.

10
Subscribe to my newsletter

Read articles from Vinay Bhardwaj directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Vinay Bhardwaj
Vinay Bhardwaj

Senior Frontend Engineer at Jio Platforms Limited.