Kat Huang‍

← Back to all writing

Why you can’t use `!important` in CSS animation `@keyframes`

December 23, 2021

While reading the MDN page for @keyframes, which are used to make CSS animations, I saw the sentence:

Declarations in a keyframe qualified with !important are ignored.

This seemed surprising. I generally have the sense that adding !important to a declaration makes that declaration “win out”, i.e. over ones that came earlier in the stylesheet and ones that lack the !important annotation.

I dug into why this is the case, and understanding it starts all the way back with what “cascading” in Cascading Style Sheets (CSS) means.

The “cascading” in Cascading Style Sheets (CSS)

One guiding principle of CSS is that multiple different stylesheets can influence how a document is presented. There are two processes that help make this happen:

  1. Cascading
  2. Defaulting

In cascading, we have different declarations trying to set values for the same combination of element and property, and the cascade figures out which one to use, based on a particular order of precedence.

Defaulting is the opposite: no declarations attempt to set a value for a given element/property combination, so the value defaults to inheriting from the parent or using a property’s initial value.

We’ll be focusing on the cascade, because the @keyframes quirk is about the conflict between regular animation declarations and !important ones.

The cascade sorting order and !important

To determine which value wins, the cascade looks at where the declaration came from. There are three core origins:

There are also two origins that arise from extensions to CSS:

The !important annotation exists to let authors or users move a declaration from its default spot in the precedence order to a certain higher one. A declaration is called important if it contains the !important annotation. Otherwise, it is normal.

Putting these categories all together, this is the cascade sorting order:

  1. Transition
  2. Important user agent
  3. Important user
  4. Important author
  5. Animation
  6. Normal author
  7. Normal user
  8. Normal user agent

Notice that the three important origins are in the reverse order of the three normal origins. As alluded to before, this can be helpful for accessibility, letting !important user origin styles override declarations that a website author deems !important.

Also, notice that all important origins, specifically the important author origin (#4), have more weight than animation (#5). This is something that the CSS specification on animations points out, and the MDN docs reflect.

Back to the main question

Once I learned all this, I thought: well, that’s enlightening, but it doesn’t fully explain… why should and why does !important not work in @keyframes? Can’t an important declaration in a keyframe just be ✨ extra-emphasized ✨ but effectively do the same thing as a normal one?

Let’s break this down into the why and the how.

The why: As mentioned above, !important provides a way to shift the balance of power among different style declaration origins. Animations already override all normal declarations, so it’s useful to have something at one’s disposal to override animations. That “something” is !important.

As for how, I looked into how animation works. It seems that the animation process as a whole looks at the keyframes and then adds appropriate values into the CSS cascade. But the declarations in the keyframes don’t directly interact with the cascade themselves. !important makes no sense outside the context of cascading(!), so important declarations are invalid and therefore ignored by the animation process.