How Does CSS Work Behind the Scenes?
A look at how HTML and CSS are processed in the browser
In this article, we’ll get a high-level overview of how HTML and CSS are processed in the browser.
Here, we’re going to learn about the CSS parsing phase.
First, let’s do a quick review of the terms we find in a CSS rule. A rule consists of a selector and a declaration block:
A selector is used to select one or more HTML elements that we want to style. Each declaration consists of a CSS property and its corresponding value. The value we assign to the property is called the declared value.
Now let’s talk about the CSS parsing phase.
Resolving Conflicting CSS Declarations: Cascading
Cascading is the process of combining different stylesheets and resolving conflicts between different CSS rules and declarations when there is more than one rule applicable to a certain element.
E.g., the font-size property can appear in several stylesheets, and also several times inside one stylesheet.
CSS comes from these different sources:
1. Author Declarations (CSS that developers write)
2. User Declarations ( settings created by the user in the browser, for example setting font-size in the browser)
3. Browser Declarations (also known as user-agent default browser declarations)
Cascade combines the CSS declarations coming from all these different sources.
But how does the cascade actually resolve conflicts? By looking at the importance, specificity, and source order of conflicting declarations in order to determine which one takes precedence.
Here is the order of how we look at the importance, specificity, and source order for all the matching rules:
A rule that has the
!important directive is always applied, no matter where that rule appears in the CSS document.
The most important declarations are user declarations marked with the important keyword. The second most important declarations are the author declarations marked with important. Third are the normal author declarations, and finally, the least important ones are the default browser declarations. This actually makes a lot of sense, so that we can easily overwrite these declarations coming by default from the browser.
Let’s look at an example to better understand:
Here we have two rules. Both apply to the
.btn class, and we have two conflicting declarations about the
background-color. Both are author declarations, but if you look closely at the first rule declaration,
background-color: #000 contains the important keyword, and therefore this declaration is more important as we can see from the above. This means this declaration will get precedence.
A lot of the time, we’ll just have a bunch of conflicting rules in our author stylesheets without any important keywords. In this case, all the declarations have the same importance. If this is the case, the cascade calculates and compares the specificities of the declaration selectors.
There are four categories which define the specificity level of a selector:
- Inline styles (highest specificity): An inline style is attached directly to the element to be styled. Example:
<h1 style=”color: #ffffff;”>.
- IDs: An ID is a unique identifier for the page elements, such as
- Classes, attributes, and pseudo-classes: This category includes
[attributes]and pseudo-classes such as
- Elements and pseudo-elements (lowest specificity): This category includes element names and pseudo-elements such as
We have four slots, and each one of them starts at zero:
- First Selector: 0 0 1 0 specificity, because it has only one class selector.
- Second Selector: 0 1 2 2 specificity, because it has one ID selector, two class selectors, and two element selectors.
- Third Selector: 0 0 0 1 specificity, because it has one element selector.
- Fourth Selector: 0 1 2 1 specificity, because it has one ID selector, one class selector, one pseudo-element, and one element selector.
Now that we have four specificities, we compare them all from left to right. Start with an inline style (most specific). If there is a selector with the inline style, that selector will win against all the other selectors, because it is the most specific category.
That’s not the case here, so let’s move on to the IDs. Here we can see that the second and fourth selectors have ID specificity of one. So, the selectors with zero are out of the game, because they are less specific than the second and fourth. Since both selectors have one in this category, we have to move on and check the next classes category. In the classes category, both the second and fourth selector have two, so we move to the next.
In the selector category, the second selector has higher specificity than the forth. The second selector is the most specific selector of all, so the
If all the declaration selectors have the same specificity, then the last declaration will be used. The last declaration in the code will overwrite all other declarations and will be applied.
- CSS declarations marked with ! important have the highest priority.
(But only use ! important as a last resort.)
- Inline styles will always have priority over styles in external stylesheets.
- The universal selector * has least specificity value (0, 0, 0, 0).
- Rely more on specificity than the order of selectors.
- When using third-party stylesheets, always put your author stylesheet last.
I hope this article is useful to you. Thanks for reading, and keep learning!