Cascading Style Sheets offers a wide range of properties and declarations that are very easy to learn and use. We can learn how each property works and use them easily to create beautiful layouts. But apart from it, there is much more that is happening behind the scenes when we load a web page. This article will take you on a journey of exploring the intricacies of CSS. Whether you are a beginner or an experienced developer seeking to level up your CSS skills, this article will surely have something for you. Are you excited? Let's get into it :)
When we load a web page, the browser first loads and parses the HTML code. HTML parsing means reading the code and taking out information like headings, paragraphs, links, etc. It is decoding the code line by line.
At this phase, after parsing the HTML, it generates the DOM (Document Object Model). According to MDN:
The Document Object Model (DOM) is the data representation of the objects that comprise the structure and content of a document on the web.
DOM is a way of representing documents by nodes and objects so that a program can change the styling and content of the web page. Being an object-oriented representation of the web page, it can be modified by scripting language like JavaScript. In simple terms, it is also called a family tree with parents, children and sibling elements.
During the parsing of HTML, the browser also finds stylesheets. At this point, it loads CSS and parses it.
Yes, you heard it right. Parsing of CSS is also done but in a different way than that of HTML. Parsing of CSS involves two steps:
Cascade
Processing final values
Let's have a look at them in detail.
- Cascade
In CSS, the cascade is the algorithm for resolving conflicts among different CSS rules applied to an element. There are various sources from which the CSS can come and arise conflicts. For example, one source of CSS is what the developer writes. Another source is the browser's default CSS. Let's take a look at the different types of sources.
Browser: This is also called user-agent-stylesheets. These are the pre-defined set of CSS rules applied to web pages by the browsers. One basic example of this is when we write an anchor tag in our HTML code then by default the text color of that anchor tag comes out to be blue with an underline. These are user-agent styles applied by browsers. Therefore it is good practice to normalize the CSS in your project.
Author: We are all familiar with this type of style sheet. This is the CSS style written by the developer which can of course override the user-agent-stylesheet.
User: This is a type of CSS that is coming from the user. In the past when the designs of web pages were not very good looking, browsers gave the ability to user to change the styles of the web page. With this ability, users can change styles like font size, background color, etc. for web pages according to their needs. This type of CSS is not common nowadays.
Above are the different sources of CSS. But how does the browser resolve conflicts when different CSS rules from different sources are applied to an element? There are there factors to be considered here.
Origin and Importance
Specificity
Source order
The priority of the above factors is from Importance to Source order in decreasing order. When different sources of CSS are there in the code, then the browser gives importance to them in the following order (high to low):
Browser
! important
declarations (highest priority)User
! important
declarationsAuthor (developer)
! important
declarationAuthor (developer) declaration
User declaration
Browser declaration (lowest priority)
In the above order ! important
is the CSS rule used to give more importance to a property than normal. As you can see, Browser (normal declaration) has the lowest priority but Browser ! important
declaration has the highest priority. After that User ! important
declaration comes and then Author (developer) ! important
and so on. Please have a look at the below code.
button {
background-color: red !important;
}
nav button {
background-color: blue;
}
In the above code snippet, both the declarations are Author declarations. But as per our priority order of "Origin and Importance", Author ! important
has higher priority than Author (normal). Hence, the color of the button will be "red".
After giving importance to the origins of CSS, the next factor is specificity. In any one origin, there can be many conflicting CSS rules. For example, in the case of an Author declaration, a developer can give different values to a property of an element. In this case, the browser calculates the specificity of the declaration selectors. Selector weights have the following order of decreasing specificity (from high to low).
Inline Styles (highest specificity)
ID
Classes
Elements (lowest specificity)
For more details on specificity, please refer to this MDN doc.
For example, please have a look at below code snippet.
#my-id button {
background-color: blue;
}
button {
background-color: red;
}
In the first declaration, we have 1 ID and 1 class. In the second, we have only 1 class. So, the first declaration is more specific than the second one. Therefore, the color of the button will be "blue". That's a very basic example of how specificity is calculated.
But what happens when two declarations have the same specificity? There comes our third factor - Order of appearance (source order). In this case, the last declaration in the code will be applied.
So far we have seen Cascade (resolving conflicts) in CSS parsing phase. Now we will move to the second step of parsing i.e., processing final values.
- Processing Final Values
Many times, when writing CSS, we give relative values to a CSS property. For example, in font size, the most common values are "rem" and "em", in the case of height, width, padding and margin, we use "%", "vh" and "vw". But to render a website in the end, the browser will need all the values into "px". So, in the end, all of the relative units are converted into "px". Let's take a look at the below example.
.parent {
background-color: yellow;
height: 100px;
}
.child {
background-color: blue;
height: 70%;
}
The child element has a height equal to 70% of the height of its parent element. The parent element has 100px height and 70% of 100 is 70px. Therefore, the child element has a height of 70px.
Here, the parsing of CSS completes.
After the parsing phase, the CSS is stored in CSS Object Model (CSSOM). CSSOM is just like DOM but for CSS. According to MDN:
The CSS Object Model is a set of APIs allowing the manipulation of CSS from JavaScript. It is much like the DOM but for the CSS rather than the HTML. It allows users to read and modify CSS styles dynamically.
Now, we have two Object Models,
DOM
CSSOM
These two together form a render tree. The render tree holds all the visible nodes with their computed styles.
After the render tree is created, the final layout of the web page is determined by Visual Formating Model.
Visual Formatting Model is an algorithm that takes each element from the render tree and generates one or more boxes according to the box model. It ensures that every element in the document is displayed in the correct size and at the correct position by considering a bunch of factors like box type, positioning scheme, stacking context, etc. The factors that the algorithm takes into consideration are given below.
Box dimensions: Box model
Box type
Positions
Stacking context
Relationship between elements in the tree
External information (e.g., viewport size, intrinsic dimensions of images, etc.).
We will see some of them in detail.
Box Model: Every element in CSS can be considered a box.
The above image shows different parts of the box. The part in the center is called the content where text, images, etc. lie. Then we have padding which is the area inside the box. The border is a line that goes around the padding. Then we put margin which is the space between boxes.
The standard CSS box model: In this type of box model any padding and border given to a box will be added to the dimensions (height and width) of the box. For example,
Total width = left border + left padding + specified width + right padding + right border
The alternative CSS box model: In this model, the width will not include paddings and borders. To give this box model to an element, set
box-sizing: border-box
on it.
Box Types: In CSS we have different types of box types. Some of them are given below.
Block Level: In this, elements are treated as blocks. These create line breaks and take 100% of the parent's width. It is produced by
display: block
.display: flex
anddisplay: table
also produces block-level boxes.Inline: Elements are treated as lines. They do not create line breaks which means the next element will appear on the same line as the previous. It does not allow to set the width and height of elements. It is produced by
display: inline
property.Inline Block: It is a mixture of block and inline. It allows you to set width and height. It is produced by
display: inline-block
property.
Positioning schemes: By specifying the positions of elements, we mention where the elements should lie in the document. Some of the positions are given below:
position: static
position: relative
position: absolute
position: fixed
position: sticky
Please refer to this MDN doc for details
Stacking Context: Stacking context is a three-dimensional positioning of an HTML element. It is done by using an imaginary z-axis pointing in the direction of the user or web page. It is a stack of layers, in which one layer can be on top of another. This is specified by the property z-index.
That's how the Visual formatting model is created. After creating this model, the web page is ready to render.
This is how the CSS works under the hood. I hope this article was helpful to you and has expanded your knowledge. I recommend you research some of the points which are not covered in this article in depth.
Enjoy Coding!