Home > Software design >  How can I reset and repeat a CSS animation?
How can I reset and repeat a CSS animation?

Time:08-31

I have created the below animation that should run for two frames, and then reset and start from the beginning again and run for a maximum of 25-30 seconds.

I am facing some issues when it comes to resetting the animation, as they are nested and delayed within each other already. When repeating the word scrolling, it runs while the frame is already in view and has not had the time to "rotate back" again.

How can I reset the animation and start over from the beginning for the next iteration exactly like the first iteration, without screwing up the timings?

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html,
body,
#banner {
  width: 320px;
  height: 320px;
  border: 1px solid black;
  position: relative;
  color: #fff;
  overflow: hidden;
}

#banner {
  background: #000;
  display: flex;
  flex-direction: row;
}

#frame-1,
#frame-2 {
  padding: 30px;
  font-size: 50px;
  width: 100%;
  height: 100%;
  position: absolute;
}

#frame-1,
#frame-2 {
  transform: translateX(150%);
}

.words {
  font-family: sans-serif;
  font-size: 20px;
  line-height: 22px;
  height: 22px;
}

.wordlist {
  position: relative;
  overflow: hidden;
  flex-grow: 1;
  padding-left: 8px;
}

.word {
  position: absolute;
  display: block;
  transform: translateY(50px);
}

.word:nth-child(1) {
  transform: translateY(0px);
}

.subheading__container {
  display: flex;
  flex-direction: row;
}

.first {
  animation: 2s ease-out 0.75s forwards slide-out;
}

.second {
  animation: 2.5s ease-out 1.5s forwards slide-in-out;
}

.third {
  animation: 2.5s ease-out 3.15s forwards slide-in-out;
}

.fourth {
  animation: 2s ease-out 4.75s forwards slide-in;
}

.slide-in-animation-1 {
  animation: 8s ease-in 1s forwards start-animation;
}

.slide-in-animation-2 {
  animation: 8s ease-in 9s forwards start-animation;
}

@keyframes start-animation {
  0% {
    transform: translateX(150%);
    display: block;
  }
  4% {
    transform: translateX(0%);
  }
  50% {
    transform: translateX(0%);
  }
  96% {
    transform: translateX(0%);
  }
  100% {
    transform: translateX(-150%);
    display: none;
  }
}

@keyframes slide-out {
  50% {
    transform: translateY(0);
  }
  100% {
    transform: translateY(-50px);
  }
}

@keyframes slide-in-out {
  0% {
    transform: translateY(50px);
  }
  25%,
  75% {
    transform: translateY(0px);
  }
  100% {
    transform: translateY(-50px);
  }
}

@keyframes slide-in {
  0% {
    transform: translateY(50px);
  }
  25%,
  100% {
    transform: translateY(0px);
  }
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Document</title>
  <style>

  </style>
</head>

<body>
  <div id="banner">
    <div id="frame-1" >
      <div >
        <p >This is</p>
        <p >heading</p>
        <div >
          <p >This&nbsp;is</p>
          <p >
            <span >the first word</span>
            <span >the second word</span>
            <span >third word</span>
            <span >fourth word</span>
          </p>
        </div>
      </div>
    </div>
    <div id="frame-2" >
      <div >
        <p >Lorem</p>
        <p >Ipsum</p>
        <p >Dolor</p>
      </div>
    </div>
  </div>
</body>

</html>

CodePudding user response:

To reset properly the whole animation, to have it done clean and consistent, the best way I think is by making them appear again by replacing them by themselves. To make it repeatedly, you can use setInterval

Here is a basic example:

const secondsToResetAnimation = 2000;

setInterval( function(){
  const animatedElement = document.getElementById('animation-reset') ;
  const clonedElement = animatedElement.cloneNode(true);
  animatedElement.parentNode.replaceChild(clonedElement, animatedElement);  
}, secondsToResetAnimation );
#animation-reset{
  position:absolute;
  animation: moveit 1s forwards;
}

@keyframes moveit {
  0% {
    left: 0;
  }
  100% {
    left: 50%;
  }
}
<h2 id="animation-reset">Basic animation reset</h2>

In your case, if I don't misunderstand, you need to make a first reset before the reset the whole animation. This may require you to define which parts of your code are cloned. By using the same technique mentioned above it would look like this:

const milisecondsFirstReset = 500;
const milisecondsSecondReset = 2000;

function resetAnimation(){
  //First Reset
  setTimeout( function(){ regenerateElements() }, milisecondsFirstReset );
  //Second Reset
  setTimeout( function(){ regenerateElements() }, milisecondsSecondReset );
}

// Run the Reset the first time
resetAnimation();

// Keep repeating the reset
setInterval( function(){ resetAnimation() }, milisecondsSecondReset);

function regenerateElements(){
  const animatedElement = document.getElementById('animation-reset') ;
  const clonedElement = animatedElement.cloneNode(true);
  animatedElement.parentNode.replaceChild(clonedElement, animatedElement);
}
#animation-reset{
  position:absolute;
  animation: moveit 1.5s forwards;
}

@keyframes moveit {
  0% {
    left: 0;
  }
  100% {
    left: 50%;
  }
}
<h2 id="animation-reset">Animation Reset</h2>

CodePudding user response:

You don't need Javascript to achieve this as CSS allows you to have several animations on one element.

As you want only two iterations of each animation we can put two on each of the animated elements, changing the wait time of the second one by adding the 17seconds that the first set of animations overall takes.

A couple of extra adjustments had to be made, on the first and last word animations to make sure they were shown correctly in the second set of animations. The fourth word is made to go to opacity 0 at the end of its animation so it doesn't show the second time round to begin with and its animation duration was increased accordingly.

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html,
body,
#banner {
  width: 320px;
  height: 320px;
  border: 1px solid black;
  position: relative;
  color: #fff;
  overflow: hidden;
}

#banner {
  background: #000;
  display: flex;
  flex-direction: row;
  --t: 17s;
  /* overall time for one complete animation */
  --i: 2;
  /* number of iterations of the complete animation */
}

#frame-1,
#frame-2 {
  padding: 30px;
  font-size: 50px;
  width: 100%;
  height: 100%;
  position: absolute;
}

#frame-1,
#frame-2 {
  transform: translateX(150%);
}

.words {
  font-family: sans-serif;
  font-size: 20px;
  line-height: 22px;
  height: 22px;
}

.wordlist {
  position: relative;
  overflow: hidden;
  flex-grow: 1;
  padding-left: 8px;
}

.word {
  position: absolute;
  display: block;
  transform: translateY(50px);
}

.subheading__container {
  display: flex;
  flex-direction: row;
}

.first {
  animation: 2s ease-out 0.75s forwards slide-out, 2s ease-out calc(17s   0.75s) forwards slide-out;
}

.second {
  animation: 2.5s ease-out 1.5s forwards slide-in-out, 2.5s ease-out calc(17s   1.5s) forwards slide-in-out;
}

.third {
  animation: 2.5s ease-out 3.15s forwards slide-in-out, 2.5s ease-out calc(17s   3.15s) forwards slide-in-out;
}

.fourth {
  animation: 4s ease-out 4.75s forwards slide-in, 4s ease-out calc(17s   4.75s) forwards slide-in;
}

.slide-in-animation-1 {
  animation: 8s ease-in 1s forwards start-animation, 8s ease-in calc(17s   1s) forwards start-animation;
}

.slide-in-animation-2 {
  animation: 8s ease-in 9s forwards start-animation, 8s ease-in calc(17s   9s) forwards start-animation-and-remain;
}

@keyframes start-animation {
  0% {
    transform: translateX(150%);
    display: block;
  }
  4% {
    transform: translateX(0%);
  }
  50% {
    transform: translateX(0%);
  }
  96% {
    transform: translateX(0%);
  }
  100% {
    transform: translateX(-150%);
    display: none;
  }
}

@keyframes start-animation-and-remain {
  0% {
    transform: translateX(150%);
    display: block;
  }
  4% {
    transform: translateX(0%);
  }
  50%,
  100% {
    transform: translateX(0%);
  }
}

@keyframes start-animation-and-remain {
  0% {
    transform: translateX(150%);
    display: block;
  }
  4% {
    transform: translateX(0%);
  }
  50%,
  100% {
    transform: translateX(0%);
  }
}

@keyframes slide-out {
  0%,
  50% {
    transform: translateY(0);
  }
  100% {
    transform: translateY(-50px);
  }
}

@keyframes slide-in-out {
  0% {
    transform: translateY(50px);
  }
  25%,
  75% {
    transform: translateY(0px);
  }
  100% {
    transform: translateY(-50px);
  }
}

@keyframes slide-in {
  0% {
    transform: translateY(50px);
    opacity: 1;
  }
  15%,
  99.99% {
    transform: translateY(0px);
    opacity: 1;
  }
  100% {
    opacity: 0;
    transform: translateY(0px);
  }
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Document</title>

</head>

<body>
  <div id="banner">
    <div id="frame-1" >
      <div >
        <p >This is</p>
        <p >heading</p>
        <div >
          <p >This&nbsp;is</p>
          <p >
            <span >the first word</span>
            <span >the second word</span>
            <span >third word</span>
            <span >fourth word</span>
          </p>
        </div>
      </div>
    </div>
    <div id="frame-2" >
      <div >
        <p >Lorem</p>
        <p >Ipsum</p>
        <p >Dolor</p>
      </div>
    </div>
  </div>
</body>

</html>

  • Related