loading...
Cover image for CSS cascade: Importance

CSS cascade: Importance

kapantzak profile image John Kapantzakis ・4 min read

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:

  1. Importance: The importance of each declaration
  2. Specificity: The specificity of the css selectors
  3. 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).

Alt Text

Lets verify the above diagram with a real example:

Alt Text

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.

Alt Text

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):

  1. Transition declarations
  2. Important user agent declarations
  3. Important user declarations
  4. Important author declarations
  5. Animation declarations
  6. Normal author declarations
  7. Normal user declarations
  8. 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:

Alt Text

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:

Alt Text

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.

Alt Text

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.

Alt Text

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.

Alt Text

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

References

Posted on by:

kapantzak profile

John Kapantzakis

@kapantzak

Web developer - want to learn something new every day

Discussion

markdown guide
 

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.

 

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:

<div class="ex one">Example</div>

<style>
.ex.one { color:red !important; }
.ex { color:blue !important; }
</style>

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