Pure CSS rotate animation broken while in infinite loop

前端 未结 2 1439
借酒劲吻你
借酒劲吻你 2021-01-14 02:26

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

2条回答
  •  小蘑菇
    小蘑菇 (楼主)
    2021-01-14 03:03

    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);
      }
    }


    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);
      }
    }

    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;
      }
    
    }

    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.

提交回复
热议问题