CSS Animation : Return div to its original position only after I stopped hovering
Asked Answered
G

2

0

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>
Graduation answered 22/3, 2023 at 4:32 Comment(0)
A
1

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>
Aloud answered 23/3, 2023 at 3:10 Comment(0)
N
0

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

Nikolas answered 22/3, 2023 at 4:39 Comment(1)
it does return but it's not reversing all the steps it already took. I need it to reverse any location that it has been to. I tried declaring transition and ease separately, but it is not working.Graduation

© 2022 - 2024 — McMap. All rights reserved.