skip to Main Content

I want my div to return to its original position in reverse right after I stop hovering. But the return starts before I even begin to hover on the div and right after running the code.

I need the reverse animation to be performed only after I stop hovering.

<!DOCTYPE html>
<html>

<head>
  <title>Page Title</title>
</head>
<style>
  div {
    width: 100px;
    height: 100px;
    padding: 2px;
    background-color: lightblue;
    color: White;
    font-size: 40px;
    text-align: center;
    vertical-align: middle;
    display: table-cell;
  }
  
  div:hover {
    animation: moveDiv 10s linear infinite;
    animation-play-state: running;
  }
  
  div:not(:hover) {
    animation: moveDiv 3s reverse ease-in;
  }
  
  @keyframes moveDiv {
    0% {
      transform: translate(0px, 0px);
    }
    25% {
      transform: translate(250px, 180px);
      background: yellow;
    }
    50% {
      transform: translate(490px, 60px);
      background: lightseagreen;
    }
    75% {
      transform: translate(550px, 390px);
      background: crimson;
    }
    100% {
      transform: translate(600px, 450px);
      background: orchid;
    }
  }
</style>

<body>

  <div>hello</div>

</body>

</html>

2

Answers


  1. Is div:not(:hover) triggering the reverse animation right after the page loads? Try adding animation-direction: reverse; to div:not(:hover).

    Login or Signup to reply.
  2. The easiest is probably to use some JS and the Web Animations API. You’d listen for the pointer events, and then control your animation status from there.

    Since you want two different durations for the forward animation and the backward one, we need to add some trickery involving setting the playback-rate of our animation:

    const forwardDur = 10_000; // in ms
    const backwardDur = 3_000; // in ms
    const box = document.querySelector(".box");
    const anim = new Animation(new KeyframeEffect(
      box,
      [
        {
          transform: "translate(0px, 0px)",
        },
        {
          transform: "translate(250px, 180px)",
          background: "yellow",
        },
        {
          transform: "translate(490px, 60px)",
          background: "lightseagreen",
        },
        {
          transform: "translate(550px, 390px)",
          background: "crimson",
        },
        {
          transform: "translate(600px, 450px)",
          background: "orchid",
        }
      ],
      { duration: forwardDur, fill: "forwards", easing: "linear" }
    ));
    
    box.onmouseenter = (evt) => {
      // We need to grab the current playState first,
      // because updatePlaybackRate() does change it
      const { playState } = anim;
      anim.updatePlaybackRate(1); // go forward at normal speed
      if (playState !== "running") { // we were either paused or finished
        anim.currentTime = 0; // get out of "finished" state
        anim.play();
      }
    };
    box.onmouseout = (evt) => {
      const { playState } = anim;
      // go backward at higher speed
      anim.updatePlaybackRate(forwardDur / backwardDur * -1);
      if (playState !== "running") { // we were either paused or finished
        anim.currentTime = forwardDur; // get out of "finished" state
        anim.play();
      }
    }
    .box {
      width: 100px;
      height: 100px;
      padding: 2px;
      background-color: lightblue;
      color: White;
      font-size: 40px;
      text-align: center;
      vertical-align: middle;
      display: table-cell;
    }
    <div class="box">hello</div>

    For a simpler case of the same speed animations in both ways, we could have used Animation#reverse():

    const box = document.querySelector(".box");
    const anim = new Animation(new KeyframeEffect(
      box,
      [
        {
          transform: "translate(0px, 0px)",
        },
        {
          transform: "translate(250px, 180px)",
          background: "yellow",
        },
        {
          transform: "translate(490px, 60px)",
          background: "lightseagreen",
        },
        {
          transform: "translate(550px, 390px)",
          background: "crimson",
        },
        {
          transform: "translate(600px, 450px)",
          background: "orchid",
        }
      ],
      { duration: 10_000, fill: "forwards" }
    ));
    anim.playbackRate = -1; // force reversed state so we can start with .reverse()
    
    box.onmouseenter = (evt) => anim.reverse();
    box.onmouseout = (evt) => anim.reverse();
    .box {
      width: 100px;
      height: 100px;
      padding: 2px;
      background-color: lightblue;
      color: White;
      font-size: 40px;
      text-align: center;
      vertical-align: middle;
      display: table-cell;
    }
    <div class="box">hello</div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search