CSS Animation Reverse not working?

Go through a few reasons why CSS reverse animations is not working with the animation-direction CSS property

Dec 22, 2021 | Read time 6 minutes

🔔 Table of contents

This article will go through a few reasons why CSS reverse animations is not working. A common use case for when you want to

reverse a CSS animation is when someone clicks on a button, a tooltip will appear. The next click will then hide the tooltip.

For example, in the below codepen, a vertical menu will appear when you click on the button. The next click will hide the menu.

As shown in the above, a common pattern is to have 2 @keyframe animations. We will have one animation for the forward playback. And another animation

for the reverse playback.

Possible issue #1 - CSS overrides

To reverse an animation, you will need to use the animation-direction CSS property. This property takes the following possible

values to indicate whether the animation should be played forwards, backwards, repeated, etc:

animation-direction: normal;
animation-direction: reverse;
animation-direction: alternate;
animation-direction: alternate-reverse;

Another way to declare it is to use the animation CSS shorthand.

/* @keyframes duration | easing-function | delay | iteration-count | direction | fill-mode | play-state | name */
animation: 3s ease-in 1s 2 reverse both paused slidein;

In the above we want to have an animation thats 3 seconds using the “ease-in” function, delayed 1 second, iterate twice, reversed, filled for both, currently paused

and uses the “slidein” @keyframe

Now your animation will not reverse if you declare your animation-direction property before the shorthand animation CSS property.

As an example, take the following style

.block {
  animation-direction: reverse;
  animation: 3s ease-in 1s 2 normal
}

From the above example, we can see that the animation-direction is declared as reverse on the top line, but then it will

be overwritten with the second shorthand animation property - changing to “normal”.

Possible issue #2 - Not specifying the browser prefixes

CSS vendor prefixes are browser specific CSS prefixes before a CSS property to allow browsers to support new

and upcoming CSS functionality. We have the following set of prefixes for each browser type:

  • -webkit- (Chrome, Safari, iOS, Android)
  • -moz- (Firefox)
  • -ms- (IE)
  • -o- (Opera)

To use the prefixes, we add the above to our CSS as follows:

-webkit-animation-delay: 3s;
-moz-animation-delay: 3s;
-ms-animation-delay: 3s;
-o-animation-delay: 3s;
animation-delay: 3s;

So when you are using the animation-direction CSS property at least add the following prefixes so that the browser

can recognise them. As an example, without the -moz- prefix, specific version of firefox, the animation delay will

not work for the user.

At the time of writing the animation-direction CSS property should be available for the most recent versions of all browsers.

Possible issue #3 - Trying to use the same @keyframe animation for both forward and reverse animation

A common use case for reversing animations is to reuse the same @keyframe animation, but when you define the animation on the element

you will change it to “reverse”. So lets consider the following CSS:

@keyframes line-in {
  0% { transform: translateY(-100px); }
  50% { transform: translateY(0); }
  100% { transform: rotate(-135deg); }
}

.line.active {
  animation-direction: normal;
}

.line {
  animation-direction: reverse;
  animation-name: line-in;
}

The intention of the above is to reverse the animation when we add the active class. This will not work because of the following issues.

  • Animations will start from 0% and then to 100% - as seen below, the animation will flow through a timeline as follows:
animation timeline explanation
  • When the active class is applied to the element, the **animation-direction ** “reverse” is applied, but you will not see the effect of reversing the animation. This is because the animation already finished at 100% in the timeline!

So to get it to actual reverse the animation, we need to apply some trickery.

  1. Reset the animation by clearing the class
  2. Trigger a DOM reflow - this is a operation taht forces the browser to recalculate the layout of the document and therefore reset any animations.
var element = document.getElementById("myElement"); 
element.classList.remove("line"); 
element.classList.remove("active"); 

// DOM reflow hack
void element.offsetWidth; 

element.classList.add("line");
element.classList.add("active");

Be warned - this type of action will be a performance hit. Its best practice to use the transition CSS property where possible or have two

different animations for forward and reverse.

Final thoughts

When animating with CSS, there are use cases when you want to reverse an animation. For example, showing a menu on a button click, and then hiding it

on the next click. We use the animation-direction CSS property withto define if the animation should move forward, backwards or alternate.

Using the “reverse” reserved word, we can set the animation to be reverse.

Additionally we can use the shorthand animation CSS property to define a reverse animation. Issues can arise when we are not carefull with setting

the order of the CSS animation-direction property vs the shorthand version, not using the correct browser prefix, or reusing the same

@keyframe animation. We can get around issues with reusing @keyframe animations, but it is best practice to separate animation @keyframes or use

transition CSS property.

👋 About the Author

G'day! I am Huy a software engineer based in Australia. I have been creating design-centered software for the last 10 years both professionally and as a passion.

My aim to share what I have learnt with you! (and to help me remember 😅)

Follow along on Twitter , GitHub and YouTube