While preparing for Microsoft's 70-480 exam I came across a question in which I had to sort different stylesheets according to their origin and importance, and I got a bit confused.
Even though I'm using CSS for more than 10 years, I've never dig into the specs to find out more about the terminology. When I finally spotted the right place in the specification it got more clear to me and I've decided to provide a simple illustration.
Cascaded value
The cascading algorithm takes an unodrered list of declared values and outputs a single value that is called the cascaded value. The algoritm takes into account 3 factors:
- Importance: The importance of each declaration
- Specificity: The specificity of the css selectors
- Order: The order of the css declarations in the source code
The following illustration presents the way that the cascade algorithm determines the final declaration (cascaded value).
Lets verify the above diagram with a real example:
We are not going to cover all 3 steps of the cascading process, instead, we are going to explain only the first step, the importance.
Just to clarify some basic terms, consider the following rule:
background-color: #ececec
The background-color
string defines a CSS property and is called a property declaration.
The #ececec
is the value given to the aforementioned property and is called the declared value.
Now, imagine that we have multiple CSS rules applied to the same element, declaring different values to the same property.
These rules may be at the same file, or may derive from different origins. The cascading algorithm has to choose one of those values to be the cascaded value.
Origin
There are 3 main origins defined in CSS:
- Author origin: The rules written by a web developer (the author of the page)
- User origin: The final user of the browser may be able to alter the user agent's default styles
- User agent origin: The default styles applied by the browser
plus 2 additions from CSS extensions
- Animation origin: Rules created by CSS animations
- Transition origin: Rules created by CSS transitions
Importance
- Normal: The default state of declarations
-
Important: Any declaration with the
!important
annotation
Order by origin and importance
Specification defines the following precedence for the above combinations in descending order (Top wins):
- Transition declarations
- Important user agent declarations
- Important user declarations
- Important author declarations
- Animation declarations
- Normal author declarations
- Normal user declarations
- Normal user agent declarations
Lets demonstarte the above hierarchy with some examples.
Normal user agent declarations
We start with a simple HTML page with only one p
element and no css declared, like this:
In this case, what style is going to be applied to the document? The answer is the default user agent style. Opening the developers tools in Chrome (Version 78.0.3904.108) we see the following:
As soon as we do not provide any kind of style, the browser applies the default user agent style.
Normal author over normal user agent declarations
Now, lets add a css file and add a rule for the p
tag:
After we reference the new css file inside out HTML, we reload the page and we inspect the p
element:
Here we can verify the precedence of normal author declaration over user agent declaration.
Animations over normal author declarations
What happens if we add an animation declaration?
According to the specification,
The last declaration in document order wins (see here)
So, we have intentionally placed the color: green
declaration after the animation declaration, in order to verify that animations takes precedence over normal author declarations, regardless of their location inside the source code.
The following screenshot illustrates the fact that animation declarations take precedence over normal author declarations, even if the latter are placed after the former, inside the source code.
Important author over normal author declarations
According to the specification
The importance of a declaration is based on whether or not it is declared
!important
The following screenshot illustrates the precedence of an important author declaration (color: blue !important
) over a normal one.
Final thoughts
We have investigated the internals of the cascade algorithm and provided some simple examples trying to verify the expected behaviour.
We have, explicitly, verified the following facts:
- Precedence of normal author over normal user agent declarations
- Precedence of animations over normal author declarations
- Precedence of important author over normal author declarations
During the process of writing this post, I have tried to verify the predence of normal author declaration over normal user declaration, but I have failed to reproduce the expected behaviour, as shown in the following screenshot.
Here, I tried to add some user style declarations (color: blue;
) using the developer tools, but it seems that this rule takes precedence over the normal author declaration (color: green;
).
For anyone interested, here is a question I've posted on Stack Overflow regarding this issue.
Chrome version 78.0.3904.108 was used for the above examples
Top comments (9)
You're missing the proper word for all this: Specificity. The order in which selectors and rules like !important are applied and/or "cascade"
That said, if you use !important in production code MOST of the time you either don't have the right selector, or there's something horrifyingly wrong with the code. Only time I've ever HAD to use !important code I've written has been in Stylus.
Still, it's good to know the rules.
You're right! "!important" should always be considered as the last option.
I'm just trying to present some simple examples in order to verify that the browser (Chrome here) implements the cascade process as indicated by the specification.
Which is good: Trust but verify!
!important actually affects the origin, not the specificity.
Origin is in a whole level above specificity when it comes to determining the cascading value
developer.mozilla.org/en-US/docs/W...
Sorry for this bit of pendantry, I used to think that, but that's not quite correct either. Rather than !important affecting the origin, think of origin and importance as complementary, and that they work together as a pair to affect the highest level of precedence within the cascade.
Specificity has nothing to do with this article. Specificity operates within each layer of the cascade, not between the layers, which is the subject of this article.
The what now? It's all sibling level specificity overrides. class can't trump !important, !important trumps !important. That's PART of specificity.
Just like class trumps tag, parent trumps children, id trumps classes, etc, etc. Like the different hands in poker. That's specificity. Just as the order is part of specificity.
Specificity -- The testing of conditions and traits of selectors and identifiers as they are applied to the document.
Unless you have an entirely different understanding of and/or definition of the term as it applies to HTML and CSS...
No. Importance is controlled by !important. Importance is part of the cascade, not part of specificity.
So, in this:
the text "Example" will be red. Because within the author stylesheet origin importance layer of the cascade, the specificity of
.ex.one
trumps the specificity of.ex
.Similarly, the order of styles is not part of specificity, but part of the cascade.
Default inheritance, on the other hand, is neither part of specificity nor the wider cascade. It applies only when the cascade fails to resolve any specified value for a property (and only then if the property is defined as an inherited one).
Great article!
What fails in the last test is that styles defined in the devtools are not user styles but inline author styles. That's why they take precedence over external author styles.
stackoverflow.com/a/59209554/9144410