How does CSS actually work?
When a user opens the page in the browser, the browser performs the following steps before rendering the web page -
- Loads the initial HTML file
- Takes loaded HTML code and parses it, which basically means it decodes the code line by line
- Then the browser builds the DOM (Document Object Model)
As the browser parses HTML it also finds the style sheets included in the HTML head. CSS is also parsed, but the parsing of CSS is a bit more complex and there are two main steps
- Conflicting CSS declarations are resolved through a process known as the cascade
- The second step is to process final CSS values
The final CSS is also stored in a tree-like structure called the CSS Object Model (CSSOM)
After the HTML and CSS are parsed and stored, these together form render tree
In order to render the page, the browser uses the algorithm called visual formatting model. this algorithm calculates and uses a bunch of stuff like the
box model, floats, and positioning
.After the visual formatting model has done its work, the website is finally rendered.
Diagram Credit - Jonas Schmedtmann
What is cascade in CSS?
We have seen that parsing of CSS includes two-phase let's take a look at the first phase which is Resolve conflicting CSS declarations (cascade)
. cascade is a process of combining different stylesheets and resolving conflict between different CSS rules and declarations when more than one rule applies to a certain element.
CSS rule -
Now CSS can also come from different sources
. the most common one is the CSS that we the developers write, and these declarations are called Author
declarations. another CSS that is coming from the user is called User
declarations. for instance when the user changes the default font size in the browser then that is User
CSS. and there are the default browser declarations which is called Browser (user agent)
CSS.
How does the cascade actually resolve conflicts when more than one rule applies?
cascade first looks at the importance
, at the selector specificity
, and the source
order of conflicting declarations in order to determine which one takes precedence.
Diagram Credit - Jonas Schmedtmann
1. IMPORTANCE
There is a special piece of CSS that you can use to overrule all of the above calculations. However, you should be very careful with using it — !important
. This is used to make a particular property and value the most specific thing, thus overriding the normal rules of the cascade
.
In the below code snippet the background color of span in themake-pink
class is declared with !important
so it has more specificity than the background color declared in the span declaration block.
<span class="make-pink">Rule everything with one selector.</span>
span {
background-color: rgb(250, 20, 231);
font-size: 2rem;
color: white;
}
.make-pink {
background-color: pink !important;
font-size: 2rem;
color: white;
}
2. SPECIFICITY
Once you understand the fact that source order matters, at some point you will run into a situation where you know that a rule comes later in the stylesheet, but an earlier, conflicting, rule is applied. This is because that earlier rule has a higher specificity
— it is more specific, and therefore is being chosen by the browser as the one that should style the element.
Inline styles have the highest specificity then followed by IDs, then classes and pseudo-classes and attribute selectors, and finally the least specific element and pseudo-element selector.
The specificity is actually not just one number, but one number for each of the four categories ie (Inline styles, IDs, classes, pseudo-elements and attribute, elements)
. for each of these, we count the number of occurrences in the selector.
we start to look at the numbers from left to right starting with the most specific category, the inline styles
. if there is a selector with 1
it wins against all the selectors because this is the most specific category. but in the above code, this is not the case. so let's move on to the IDs we see that selector 2 has 1
here. so the winner is the selector 2 because it's the most specific selector of all.
The universal selector * has no specific value (0, 0, 0, 0)
3. SOURCE ORDER
In source order, if all the declarations selectors have the same specificity then simply the last declaration that will be used to style the selected element.
Processing the final CSS values
This is the final step of parsing CSS. point to remember the default font size of the content on a webpage is always 16px, but you can change it at any point in time. Also, we should never set the font size in pixels. it's bad practice and a bad user experience. we should always use a rem (1rem = 16px)
. and processing final values includes multiple steps -
Declared values -
These values are declared by the author when writing a document like a developer declared a font size for the heading is font-size : 2rem
. this is called an author value.
Cascaded values -
The cascade value represents the result of the cascade. consider the below code snippet we declared the font size of the paragraph in p tag
and .main
class and here is a conflict. for resolving this we will use cascade which we have seen above. we know classes have more precedence than elements so the font size for paragraph 2rem
will be applied.
<p class="main">Hello there!</p>
p{
font-size: 1.5rem;
}
.main{
font-size: 2rem;
}
Specified values -
The specified values is the value that the author declared inside the style sheet.
most of the times specified values
are the cascade values
. if there are no cascade values then the specified value has defaulted.
Computed values -
In this relative values like ('em', 'ex', 'vh', 'vw')
is converted into absolute value.
Used values -
The used values is the result of taking the computed value
and calculating if there are any relative values is remaining.
Actual value -
A used value is in principle ready to be used, but a user agent may not be able to make use of the value in a given environment. the actual value
is the used value after any browser adjustments.
Inheritance
In simple terms, Inheritance is something passed down from your parents to you. In CSS, inheritance controls what happens when no value is specified for a property on an element. and it's categorized into two types:
- inherited properties
- non-inherited properties
- Inherited properties
When we do not specify an inherited property on an element then the computed value
of parent elements
will be applied.
<h3>We are learning <b>inheritance</b> in CSS</h3>
h3{
color:pink;
}
the word "inheritance" will appear pink since the b
elements have inherited the value of the color
property from the h3
element.
- Non-inherited properties
When no value for a non-inherited property has been specified on an element, the element gets the initial value of that property.
<h3>We are learning <b>inheritance</b> in CSS</h3>
h3{
border: medium solid;
}
the words "inheritance" will not have a border (since the initial value of border-style is none).
Well now both HTML
and CSS
have been parsed
and stored into their object models
, they both form the Render Tree
. It’s formed with a combination of HTML, DOM, and CSSDOM
. It’s used to calculate the layout of each element on the page and helps render the page.
After the render tree has been formed, the website uses something known as the Visual Formatting model
, which we can see in the first figure. A Visual Formatting model is an algorithm that calculates the boxes and the box sizes
for each element on the webpage and helps lay those elements on the page to determine the final layout of the page.
Conclusion
The main focus of this blog is to introduce you to how CSS works behind the scenes. one point to note is that !important
has the highest precedence and we should use rem
units instead of pixels. by assigning rem
units to root elements we can control every other element easily.
Thank you for reading. 🙏
If you enjoyed this article or found it helpful, give it a thumbs-up. 👍
Content Credit - Jonas Schmedtmann, MDN Web Docs
Let's Connect. 👋