Day 74: using !important in cascade layers

posted on

It’s time to get me up to speed with modern CSS. There’s so much new in CSS that I know too little about. To change that I’ve started #100DaysOfMoreOrLessModernCSS. Why more or less modern CSS? Because some topics will be about cutting-edge features, while other stuff has been around for quite a while already, but I just have little to no experience with it.


In order to understand how !important works in cascade layers, you have to understand how !important works generally. The conclusion of this post might not be what you expect.

The basics

Let's start nice and easy. We have two declarations with the same specificity. The second one wins because it comes later in the document.

h1 {
  color: green;
}

h1 {
  color: red;
}

I'm red

Adding !important to the first declaration increases its specificity, turning the color green.

h1 {
  color: green !important;
}

h1 {
  color: red;
}

I'm green

So far, so good. I assume that most of you already knew that. Now let’s have a look at cascade layers and what happens if we use !important in layers.

Layers

We have two layers, each with a declaration with the same specificity. The second declaration wins because it’s in a layer defined later in the document.

@layer base {
  h1 {
    color: green;
  }
}

@layer components {
  h1 {
    color: red;
  }
}

I'm red

If we add un-layered styles, the color turns blue because un-layered styles have precedence over layered styles.

h1 {
  color: blue;
}

@layer base {
  h1 {
    color: green;
  }
}

@layer components {
  h1 {
    color: red;
  }
}

I'm blue

If we add !important to the declaration in the base layer, the color turns green.

h1 {
  color: blue;
}

@layer base {
  h1 {
    color: green !important;
  }
}

@layer components {
  h1 {
    color: red;
  }
}

I'm green

Okay, I have to stop here for a moment. All this makes sense to me. Here’s what I thought happens before I wrote this blog post:

By default, our order of precedence is like this:

  1. Un-layered styles (most important)
  2. components layer
  3. base layer (least important)

Demo 3 and 4 confirm that.

If we add !important to the declaration in the base layer, our order looks like this:

  1. !important base layer (most important)
  2. Un-layered styles
  3. components layer
  4. base layer (least important)

Demo 5 confirms that.

If I keep extending my logic, this would mean that if we add !importantto the components layer, the order looks like this:

  1. !important components layer (most important)
  2. !important base layer
  3. Un-layered styles
  4. components layer
  5. base layer(least important)

Let’s try!

h1 {
  color: blue;
}

@layer base {
  h1 {
    color: green !important;
  }
}

@layer components {
  h1 {
    color: red !important;
  }
}

I'm green

Nooope, not red, still green. To explain why, let's have a look at the spec.

“CSS attempts to create a balance of power between author and user style sheets. By default, rules in an author’s style sheet override those in a user’s style sheet, which override those in the user-agent’s default style sheet. To balance this, a declaration can be marked important, which increases its weight in the cascade and inverts the order of precedence(emphasis mine).

CSS Cascading and Inheritance Level 3

This means that !important doesn't just increase the weight of a declaration in the cascade, but it inverts the order of precedence. So, in our first basic example !important doesn't just make the first declaration more important, no, it inverts the order of precedence!

h1 {
  color: green !important;
}

h1 {
  color: red;
}

If we make the first declaration important, this…

  1. h1 color red (most important)
  2. h1 color green (least important)

…becomes this:

  1. h1 color green (most important)
  2. h1 color red (least important)

Before cascade layers, this didn’t really matter, but now, with multiple layers on the author level, understanding this concept is critical. If we apply this logic to our last layer example, we get this:

  1. !important base layer (most important)
  2. !important components layer
  3. !important un-layered styles
  4. Un-layered styles
  5. components layer
  6. base layer(least important)

So, even if we add !important to the un-layered styles, the declaration in the base layer still wins.

h1 {
  color: blue !important;
}

@layer base {
  h1 {
    color: green !important;
  }
}

@layer components {
  h1 {
    color: red !important;
  }
}

I'm still green

Got it? No? Don't worry. It took me more than an hour to understand it. This video by Una Kravets helped a lot:

See on CodePen

Further reading

Overview: 100 Days Of More Or Less Modern CSS