Search code examples
javascriptcssanimationweb-animations

Avoiding jerky animation when using mouseover and mouseout


I am using Web Animation API to create a simple animation so that when a user moves the mouse on the target, the animation should start from left to right and when the user moves the mouse off the target, the animation should get reversed and the target should move from right to left.

Currently if the user moves the mouse in/out during animation, the animation is jerky, and I don't have a smooth effect.

I would like to know how to solve this issue.

Note: Currently I am using the Web Animation API. But the same issue occurs when using the CSS Keyframe Animation.

I have also tried to solve this issue using the following solution, which improved the situation but it's still problematic. Here is a live example https://jsfiddle.net/x784xwoa/5/

var elm = document.getElementById("target");
var player = document.getElementById("target");

elm.addEventListener('mouseover', function(event) {
  console.log('mouseover', player.playState, 'animate');
  player = elm.animate(
    [{
      left: "0px",
      boxShadow: 'rgba(0, 0, 0, 0.5) 0px 0px 0px 0px'
    }, {
      left: "100px",
      boxShadow: 'rgba(0, 0, 0, 0.9) 50px 150px 100px 0px'
    }], {
      duration: 3000,
      direction: "normal",
      fill: "forwards",
      iterations: 1
    }
  );
});

elm.addEventListener('mouseout', function(event) {
  console.log('mouseout', player.playState, 'reverse');
  player.reverse();
});
#target {
  position: relative;
  top: 0;
  left: 0;
  width: 100px;
  height: 150px;
  background-color: red;
}
<div id="target"></div>


Solution

  • I was able to solve this issue using the following script adding some logic to check playState. In case you have a better solution, please post it as answer as I would be really interested to have your feedback.

       document.addEventListener("DOMContentLoaded", function (event) {
                var elm = document.getElementById("target");
                var player = null;
    
    
    
                elm.addEventListener('mouseenter', function (event) {
                    if (player === null) {
                        player = elm.animate(
                          [{
                              left: "0px",
                              boxShadow: 'rgba(0, 0, 0, 0.5) 0px 0px 0px 0px'
                          }, {
                              left: "100px",
                              boxShadow: 'rgba(0, 0, 0, 0.9) 50px 150px 100px 0px'
                          }], {
                              duration: 3000,
                              direction: "normal",
                              fill: "forwards",
                              iterations: 1
                          }
                        );
                    }
                    else if (player.playState === 'running') {
                        player.reverse();
                    }
                    else if (player.playState === 'finished') {
                        player.reverse();
    
                    }
                });
    
                elm.addEventListener('mouseout', function (event) {
                    if (player.playState === 'running' || player.playState === 'finished') {
                        player.reverse();
                    }
                });
    
                setInterval(function () {
                    if (player) {
                        console.log(player.playState);
                    }
                }, 1000);
    
    
            });
            #target {
                position: relative;
                top: 0;
                left: 0;
                width: 100px;
                height: 150px;
                background-color: red;
            }
        <div id="target"></div>