How is CSS applied to your document?
Tags: css, webdev, html
Published: 2020-01-05 23:39:13

This week I was debugging an issue with the CSS of the application we are building at a client. It turned out that the CSS was applied to the document in an order that I wasn't expecting. It's about time for me to learn how CSS is applied to HTML documents.

## How and when is CSS loaded?
Before we have a look at how the CSS is applied to a page, the CSS needs to be loaded first. This happens in the following way. 

1) First, the Browser loads an HTML file
2) The HTML file is converted to the Document Object Model (DOM)
3) The browser fetches resources, like CSS or JavaScript 
4) The browser parses the CSS and applies the style
5) A render tree is created
6) Lastly, the page is displayed

There are two important ways that CSS is applied to a page, its cascading order and the specificity. 

## Cascading Order

The CSS that is applied to a page can come from different origins. The cascading order determines what origin to apply first. 

There are 3 different origins the CSS can come from:
- _User-Agent_; These style sheets come from the browser and can be real style sheets or hardcoded values.
- _Author_; These are the most common style sheets, the style sheets that are added to a website.
- _User_; It's possible for users to override the style sheets and customize the look.

The order in which the origins are applied is:

|  |  Origin |  |
| -------------: | ------------- | ----- |
| 1 | User Agent | normal |
| 2 | User | normal |
| 3 | Author | normal |
| 4 | Animations | |
| 5 | Author | !important | 
| 6 | User| !important | 
| 7 | User Agent | !important | 
| 8 | Transitions | | 


Note that later defined styles within the same origin win. 

Another thing that you need to keep in mind is animations. The `@keyframes` rules work a little bit different. They don't cascade and don't mix together. If multiple `@keyframes` are defined, the last one is chosen.  

## Specificity

Within the cascading of origins, the specificity of the CSS is used. 
The specificity is calculated by adding weights to the different declarations:
- 0 for `*`
- 1 for elements (`h1`, `div`) and pseudo-elements (`:before`, `:after`)
- 10 for classes (`.something`), attributes(`[some-attrib]`) and pseudo-classes (`:hover`)
- 100 for IDs (`#specific-ID`)
- 1000 for inline styles (`<div style="color:#ff0000">`)

Of course in CSS these will be combined which means the values are added together.

A few examples: 
{% gist https://gist.github.com/sorskoot/8c88438e18aee4b98965fd1a5b471734 file=specificity-weight.html %}

If we have a look at the following CSS, a few things happen there:
{% gist https://gist.github.com/sorskoot/8c88438e18aee4b98965fd1a5b471734 file=specificity.css %}

The text on a div with the ID `some-id` will be _red_. This is because line 1 calculates to 101 (an ID and an Element). The second line only calculates to 100, the last one calculates to 11 (and element and an attribute).

Now assume we have an `H1` on the page. Without a class, this will become _purple_. Because the latest defined rule wins. If we would add a class (`some-class`) the text becomes _yellow_, a class is more specific than the element.
 
I think I get it now :)