Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pure CSS rotate animation broken while in infinite loop

It's been a while since I asked a question here. So excuse me if I do anything wrong.

I have an issue with CSS animation. I would like my animation to keep repeating it self but without loosing the initial effects. However it seems like there is a bug either in my code or in CSS animation behavior.

After it completes first 2 rotate animations (spin, spinback) defined. The loop begins but the new animation is not as same as before.

My goal is to create rotate animation on 6 boxes in order, one at a time. When all boxes turned, they should start turning back to original state again in order, one by one.

Code:

/* -------------------------------------------------------- */
#loader {
  width: 240px;
  height: 100px;
}

.inner {
  position: relative;
  width: 100%;
  height: 100%;
  text-align: center;
  transition: transform 2s;
  transform-style: preserve-3d;
  background-color: transparent;
}

.front,
.back {
  position: absolute;
  width: 80px;
  height: 50px;
  backface-visibility: hidden;
}


/* -------------------------------------------------------- */

#loader1 {
  float: left;
  width: 80px;
  height: 50px;
  perspective: 1000px;
  background-color: transparent;
}

#loader1 .inner {
  animation: spin 10s ease 0s infinite, spinback 10s ease 10s infinite;
  -webkit-animation: spin 10s ease 0s infinite, spinback 10s ease 10s infinite;
}

#loader1 .front {
  background-color: #db9834;
}

#loader1 .back {
  background-color: #3498db;
  transform: rotateY(180deg);
}


/* -------------------------------------------------------- */

#loader2 {
  float: left;
  width: 80px;
  height: 50px;
  perspective: 1000px;
  background-color: transparent;
}

#loader2 .inner {
  animation: spin 10s ease 1s infinite, spinback 10s ease 11s infinite;
  -webkit-animation: spin 10s ease 1s infinite, spinback 10s ease 11s infinite;
}

#loader2 .front {
  background-color: #db8834;
}

#loader2 .back {
  background-color: #3488db;
  transform: rotateY(180deg);
}


/* -------------------------------------------------------- */

#loader3 {
  float: left;
  width: 80px;
  height: 50px;
  perspective: 1000px;
  background-color: transparent;
}

#loader3 .inner {
  animation: spin 10s ease 2s infinite, spinback 10s ease 12s infinite;
  -webkit-animation: spin 10s ease 2s infinite, spinback 10s ease 12s infinite;
}

#loader3 .front {
  background-color: #db7834;
}

#loader3 .back {
  background-color: #3478db;
  transform: rotateY(180deg);
}


/* -------------------------------------------------------- */

#loader4 {
  float: left;
  width: 80px;
  height: 50px;
  perspective: 1000px;
  background-color: transparent;
}

#loader4 .inner {
  animation: spin 10s ease 3s infinite, spinback 10s ease 13s infinite;
  -webkit-animation: spin 10s ease 3s infinite, spinback 10s ease 13s infinite;
}

#loader4 .front {
  background-color: #db6834;
}

#loader4 .back {
  background-color: #3468db;
  transform: rotateY(180deg);
}


/* -------------------------------------------------------- */

#loader5 {
  float: left;
  width: 80px;
  height: 50px;
  perspective: 1000px;
  background-color: transparent;
}

#loader5 .inner {
  animation: spin 10s ease 4s infinite, spinback 10s ease 14s infinite;
  -webkit-animation: spin 10s ease 4s infinite, spinback 10s ease 14s infinite;
}

#loader5 .front {
  background-color: #db5834;
}

#loader5 .back {
  background-color: #3458db;
  transform: rotateY(180deg);
}


/* -------------------------------------------------------- */

#loader6 {
  float: left;
  width: 80px;
  height: 50px;
  perspective: 1000px;
  background-color: transparent;
}

#loader6 .inner {
  animation: spin 10s ease 5s infinite, spinback 10s ease 15s infinite;
  -webkit-animation: spin 10s ease 5s infinite, spinback 10s ease 15s infinite;
}

#loader6 .front {
  background-color: #db4834;
}

#loader6 .back {
  background-color: #3448db;
  transform: rotateY(180deg);
}

@-webkit-keyframes spin {
  0% {
    -webkit-transform: rotateY(0deg);
  }
  16% {
    -webkit-transform: rotateY(180deg);
  }
  100% {
    -webkit-transform: rotateY(180deg);
  }
}

@keyframes spin {
  0% {
    -webkit-transform: rotateY(0deg);
  }
  16% {
    -webkit-transform: rotateY(180deg);
  }
  100% {
    -webkit-transform: rotateY(180deg);
  }
}

@-webkit-keyframes spinback {
  0% {
    -webkit-transform: rotateY(180deg);
  }
  16% {
    -webkit-transform: rotateY(0deg);
  }
  100% {
    -webkit-transform: rotateY(0deg);
  }
}

@keyframes spinback {
  0% {
    -webkit-transform: rotateY(180deg);
  }
  16% {
    -webkit-transform: rotateY(0deg);
  }
  100% {
    -webkit-transform: rotateY(0deg);
  }
}
<div id="loader">
  <div id="loader1">
    <div class="inner">
      <div class="front">
      </div>
      <div class="back"> </div>
    </div>
  </div>
  <div id="loader2">
    <div class="inner">
      <div class="front"> </div>
      <div class="back"> </div>
    </div>
  </div>
  <div id="loader3">
    <div class="inner">
      <div class="front"> </div>
      <div class="back"> </div>
    </div>
  </div>
  <div id="loader4">
    <div class="inner">
      <div class="front"> </div>
      <div class="back"> </div>
    </div>
  </div>
  <div id="loader5">
    <div class="inner">
      <div class="front"> </div>
      <div class="back"> </div>
    </div>
  </div>
  <div id="loader6">
    <div class="inner">
      <div class="front"> </div>
      <div class="back"> </div>
    </div>
  </div>
</div>

Just to make it more understandable I am trying to apply css flipcard method:

https://www.w3schools.com/howto/howto_css_flip_card.asp

On divs in order to create a look like something is loading...

The animation only gives timing to trigger keyframes in right timing then in key frames I am rotating divs and putting a wait time until oter divs finishes their rotation. So formula is 6 box in 10sec which is gonna be somewhere between (0% to 100%) so (100 / 6 = 16,6) which I take the animation as should end at 16% of the animation time.

like image 729
Berker Yüceer Avatar asked Mar 03 '23 19:03

Berker Yüceer


2 Answers

First I would simplify your code and use less HTML/CSS. Then I would consider only one animation where I will have both states.

The animation will be: the first flip then we keep the first color then the second filp then we keep the second color. It's divided into 12 time slots (1 + 5 + 1 + 5) (1+5 = 6 which is the number of the divs)

If the duration is S then the delay should be multiple of one slot S/12. Notice that I have used the perspective within the transform to avoid an extra element:

#loader {
  width: 240px;
  height: 100px;
  display: flex;
  flex-wrap: wrap;
}

#loader>div {
  width: calc(100%/3);
  position: relative;
  transform-style: preserve-3d;
  animation: spin 6s linear var(--delay, 0s) infinite;
}

#loader>div:before,
#loader>div:after {
  content: "";
  position: absolute;
  top:0;
  left:0;
  width: 100%;
  height: 100%;
  backface-visibility: hidden;
  background-color: var(--front, #db9834);
}

#loader>div:after {
  background-color: var(--back, #3498db);
  transform: rotateY(180deg);
}


/* -------------------------------------------------------- */

#loader>div:nth-child(2) {
  --front: #db8834;
  --back: #3488db;
  --delay: 0.5s;
}

#loader>div:nth-child(3) {
  --front: #db7834;
  --back: #3478db;
  --delay: 1s;
}

#loader>div:nth-child(4) {
  --front: #db6834;
  --back: #3468db;
  --delay: 1.5s;
}

#loader>div:nth-child(5) {
  --front: #db5834;
  --back: #3458db;
  --delay: 2s;
}

#loader>div:nth-child(6) {
  --front: #db4834;
  --back: #3448db;
  --delay: 2.5s;
}


@keyframes spin {
  0% {
    transform:perspective(500px) rotateY(0deg);
  }
  8.33%,
  50%{
    transform:perspective(500px) rotateY(180deg);
  }
  58.33% {
    transform:perspective(500px) rotateY(0deg);
  }
}
<div id="loader">
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
</div>

Related questions for more details about the difference between perspective and perspective()

CSS 3d transform doesn't work if perspective is set in the end of property

perspective and translateZ moves diagonally


We can simplify more if we change the div coloration while rotating instead of having two elements. The change should be made at half the slot where we do the flip (first and sixth) without any transition to create the illusion:

#loader {
  width: 240px;
  height: 100px;
  display: flex;
  flex-wrap: wrap;
}

#loader>div {
  width: calc(100%/3);
  animation: 
    spin   6s linear var(--delay, 0s) infinite,
    colors 6s linear var(--delay, 0s) infinite;
  background-color: var(--front, #db9834);
}


/* -------------------------------------------------------- */

#loader>div:nth-child(2) {
  --front: #db8834;
  --back: #3488db;
  --delay: 0.5s;
}

#loader>div:nth-child(3) {
  --front: #db7834;
  --back: #3478db;
  --delay: 1s;
}

#loader>div:nth-child(4) {
  --front: #db6834;
  --back: #3468db;
  --delay: 1.5s;
}

#loader>div:nth-child(5) {
  --front: #db5834;
  --back: #3458db;
  --delay: 2s;
}

#loader>div:nth-child(6) {
  --front: #db4834;
  --back: #3448db;
  --delay: 2.5s;
}


@keyframes spin {
  0% {
    transform:perspective(500px) rotateY(0deg);
  }
  8.33%,
  50%{
    transform:perspective(500px) rotateY(180deg);
  }
  58.33% {
    transform:perspective(500px) rotateY(0deg);
  }
}
@keyframes colors {
  0%,4.15% {
    background-color: var(--front, #db9834);
  }
  4.16% {
    background-color: var(--back, #3498db);
  }
  54.15% {
    background-color: var(--back, #3498db);
  }
  54.16% {
    background-color: var(--front, #db9834);
  }
}
<div id="loader">
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
</div>

Another simplification can be done using filter considering the fact that you want to have the same shades of colors:

#loader {
  width: 240px;
  height: 100px;
  display: flex;
  flex-wrap: wrap;
}

#loader>div {
  width: calc(100%/3);
  animation: 
    spin   6s linear var(--delay, 0s) infinite,
    colors 6s linear var(--delay, 0s) infinite;
  background: 
    linear-gradient(#db9834 50%, #3498db 0);
  background-size: 100% 200%;
}


/* -------------------------------------------------------- */

#loader>div:nth-child(2) {
  filter: brightness(0.9);
  --delay: 0.5s;
}

#loader>div:nth-child(3) {
  filter: brightness(0.8);
  --delay: 1s;
}

#loader>div:nth-child(4) {
  filter: brightness(0.7);
  --delay: 1.5s;
}

#loader>div:nth-child(5) {
  filter: brightness(0.6);
  --delay: 2s;
}

#loader>div:nth-child(6) {
  filter: brightness(0.5);
  --delay: 2.5s;
}


@keyframes spin {
  0% {
    transform:perspective(500px) rotateY(0deg);
  }
  8.33%,
  50%{
    transform:perspective(500px) rotateY(180deg);
  }
  58.33% {
    transform:perspective(500px) rotateY(0deg);
  }
}
@keyframes colors {
  4.15% {
    background-position: top;
  }
  4.16%,
  54.15% {
    background-position:bottom;
  }
  54.16% {
    background-position: top;
  }

}
<div id="loader">
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
</div>

This result is not exactly the same as I used a random filter but you can easily try another kind of filtration to get the needed result.

like image 191
Temani Afif Avatar answered Mar 06 '23 10:03

Temani Afif


A similar problem has already been described on SO: How to have the object not revert to its initial position after animation has run? The problem is that at the beginning of the animation, the object returns to its original state. But I solved the problem differently: I simply combined both animations into one, and now both reversals are described by one function. If you definitely need both animations, then redo it, as stated in the question I've given link to. Here is my code:

#loader {
  width: 240px;
  height: 100px;
}

.inner {
  position: relative;
  width: 100%;
  height: 100%;
  text-align: center;
  transition: transform 2s;
  transform-style: preserve-3d;
  background-color: transparent;
}

.front,
.back {
  position: absolute;
  width: 80px;
  height: 50px;
  backface-visibility: hidden;
}

#loader1 {
  float: left;
  width: 80px;
  height: 50px;
  perspective: 1000px;
  background-color: transparent;
}

#loader1 .inner {
  animation: spin 20s ease 0s infinite;
  -webkit-animation: spin 20s ease 0s infinite;
}

#loader1 .front {
  background-color: #db9834;
}

#loader1 .back {
  background-color: #3498db;
  transform: rotateY(180deg);
}

/* -------------------------------------------------------- */

#loader2 {
  float: left;
  width: 80px;
  height: 50px;
  perspective: 1000px;
  background-color: transparent;
}

#loader2 .inner {
  animation: spin 20s ease 1s infinite;
  -webkit-animation: spin 20s ease 1s infinite;
}

#loader2 .front {
  background-color: #db8834;
}

#loader2 .back {
  background-color: #3488db;
  transform: rotateY(180deg);
}


/* -------------------------------------------------------- */

#loader3 {
  float: left;
  width: 80px;
  height: 50px;
  perspective: 1000px;
  background-color: transparent;
}

#loader3 .inner {
  animation: spin 20s ease 2s infinite;
  -webkit-animation: spin 20s ease 2s infinite;
}

#loader3 .front {
  background-color: #db7834;
}

#loader3 .back {
  background-color: #3478db;
  transform: rotateY(180deg);
}


/* -------------------------------------------------------- */

#loader4 {
  float: left;
  width: 80px;
  height: 50px;
  perspective: 1000px;
  background-color: transparent;
}

#loader4 .inner {
  animation: spin 20s ease 3s infinite;
  -webkit-animation: spin 20s ease 3s infinite;
}

#loader4 .front {
  background-color: #db6834;
}

#loader4 .back {
  background-color: #3468db;
  transform: rotateY(180deg);
}


/* -------------------------------------------------------- */

#loader5 {
  float: left;
  width: 80px;
  height: 50px;
  perspective: 1000px;
  background-color: transparent;
}

#loader5 .inner{ 
  animation: spin 20s ease 4s infinite;
  -webkit-animation: spin 20s ease 4s infinite;
}

#loader5 .front {
  background-color: #db5834;
}

#loader5 .back {
  background-color: #3458db;
  transform: rotateY(180deg);
}


/* -------------------------------------------------------- */

#loader6 {
  float: left;
  width: 80px;
  height: 50px;
  perspective: 1000px;
  background-color: transparent;
}

#loader6 .inner {
  animation: spin 20s ease 5s infinite;
  -webkit-animation: spin 20s ease 5s infinite;
}

#loader6 .front {
  background-color: #db4834;
}

#loader6 .back {
  background-color: #3448db;
  transform: rotateY(180deg);
}


@-webkit-keyframes spin {
  0% {
    -webkit-transform: rotateY(0deg);
  }
  8% {
    -webkit-transform: rotateY(180deg);
  }
  50% {
    -webkit-transform: rotateY(180deg);
  }
  
  58% {
    -webkit-transform: rotateY(0deg);
  }
  
  100% {
    -webkit-transform: rotateY(0deg);
  }
}

@keyframes spin {
  0% {
    -webkit-transform: rotateY(0deg);
  }
  8% {
    -webkit-transform: rotateY(180deg);
  }
  50% {
    -webkit-transform: rotateY(180deg);
  }
  
  58% {
    -webkit-transform: rotateY(0deg);
  }
  
  100% {
    -webkit-transform: rotateY(0deg);
  }
}
<div id="loader">
  <div id="loader1">
    <div class="inner">
      <div class="front">
      </div>
      <div class="back"> </div>
    </div>
  </div>
  <div id="loader2">
    <div class="inner">
      <div class="front"> </div>
      <div class="back"> </div>
    </div>
  </div>
  <div id="loader3">
    <div class="inner">
      <div class="front"> </div>
      <div class="back"> </div>
    </div>
  </div>
  <div id="loader4">
    <div class="inner">
      <div class="front"> </div>
      <div class="back"> </div>
    </div>
  </div>
  <div id="loader5">
    <div class="inner">
      <div class="front"> </div>
      <div class="back"> </div>
    </div>
  </div>
  <div id="loader6">
    <div class="inner">
      <div class="front"> </div>
      <div class="back"> </div>
    </div>
  </div>
</div>
like image 26
Ver Nick Avatar answered Mar 06 '23 08:03

Ver Nick