Search code examples
csscss-animationskeyframe

CSS Animation keyframe calculations


I'm working on a css text slider animation. It originally had 5 items but I've removed one so now there are 4.

I'm having trouble with the keyframe calculations. There is a bit of a pause when the last item slides out and the first item slides back in again. It was all working fine when it had 5 items but removing one has affected the timings.

HTML:

<div class="content-slider">
  <div class="slider">
    <div class="mask">
      <ul>
        <li class="anim1">
          <div class="quote"> Service to 200+ countries</div>
        </li>
        <li class="anim2">
          <div class="quote">Same day delivery services</div>
        </li>
        <li class="anim3">
          <div class="quote">Easy booking tools.</div>
        </li>
        <li class="anim4">
          <div class="quote">Rated great.</div>
        </li>
      </ul>
    </div>
  </div>
</div> 

CSS:

html,
body {
  font-family: 'Droid Serif', serif;
}

h1 {
  font-size: 60px;
  text-align: center;
}

.content-slider {
  width: 100%;
  height: 360px;
}

.slider {
  height: 320px;
  width: 680px;
  margin: 40px auto 0;
  overflow: visible;
  position: relative;
}

.mask {
  overflow: hidden;
  height: 320px;
}

.slider ul {
  margin: 0;
  padding: 0;
  position: relative;
}

.slider li {
  width: 680px;
  height: 320px;
  position: absolute;
  right: -325px;
  list-style: none;
}

.slider .quote {
  font-size: 40px;
  font-style: italic;
  text-align:center;
}

.slider li.anim1 {
  animation: cycle 12s linear infinite;
}

.slider li.anim2 {
  animation: cycle2 12s linear infinite;
}

.slider li.anim3 {
  animation: cycle3 12s linear infinite;
}

.slider li.anim4 {
  animation: cycle4 12s linear infinite;
}

@keyframes cycle {
  0% {
    right: 0px;
  }
  4% {
    right: 0px;
  }
  16% {
    right: 0px;
    opacity: 1;
    z-index: 0;
  }
  20% {
    right: 325px;
    opacity: 0;
    z-index: 0;
  }
  21% {
    right: -325px;
    opacity: 0;
    z-index: -1;
  }
  50% {
    right: -325px;
    opacity: 0;
    z-index: -1;
  }
  92% {
    right: -325px;
    opacity: 0;
    z-index: 0;
  }
  96% {
    right: -325px;
    opacity: 0;
  }
  100% {
    right: 0px;
    opacity: 1;
  }
}

@keyframes cycle2 {
  0% {
    right: -325px;
    opacity: 0;
  }
  16% {
    right: -325px;
    opacity: 0;
  }
  20% {
    right: 0px;
    opacity: 1;
  }
  24% {
    right: 0px;
    opacity: 1;
  }
  36% {
    right: 0px;
    opacity: 1;
    z-index: 0;
  }
  40% {
    right: 325px;
    opacity: 0;
    z-index: 0;
  }
  41% {
    right: -325px;
    opacity: 0;
    z-index: -1;
  }
  100% {
    right: -325px;
    opacity: 0;
    z-index: -1;
  }
}

@keyframes cycle3 {
  0% {
    right: -325px;
    opacity: 0;
  }
  36% {
    right: -325px;
    opacity: 0;
  }
  40% {
    right: 0px;
    opacity: 1;
  }
  44% {
    right: 0px;
    opacity: 1;
  }
  56% {
    right: 0px;
    opacity: 1;
    z-index: 0;
  }
  60% {
    right: 325px;
    opacity: 0;
    z-index: 0;
  }
  61% {
    right: -325px;
    opacity: 0;
    z-index: -1;
  }
  100% {
    right: -325px;
    opacity: 0;
    z-index: -1;
  }
}

@keyframes cycle4 {
  0% {
    right: -325px;
    opacity: 0;
  }
  56% {
    right: -325px;
    opacity: 0;
  }
  60% {
    right: 0px;
    opacity: 1;
  }
  64% {
    right: 0px;
    opacity: 1;
  }
  76% {
    right: 0px;
    opacity: 1;
    z-index: -1;
  }
  80% {
    right: 325px;
    opacity: 0;
    z-index: -1;
  }
  81% {
    right: -325px;
    opacity: 0;
    z-index: -1;
  }
  100% {
    right: -325px;
    opacity: 0;
    z-index: -1;
  }
}

It's the final cycle4 animation that I've tried tweaking but I can't get the smooth transition from last to first working as it was.

Here's a codepen example


Solution

  • If you want your animation to remain 12s long then you need to realise that with 4 items, each item has 3s worth of animation time, and that every 1s of the animation is 8.33333% of the total animation time.

    If you struggle visualising this kind of thing I'd advise setting up a spreadsheet or something to do the calculations:

    calculation

    You can then easily see the percentages of your keyframes as you change parameters such as the animation length and in/out time. Anyway, here's the snippet:

    html,
    body {
      font-family: 'Droid Serif', serif;
    }
    
    h1 {
      font-size: 60px;
      text-align: center;
    }
    
    .content-slider {
      width: 100%;
      height: 360px;
    }
    
    .slider {
      height: 320px;
      width: 680px;
      margin: 40px auto 0;
      overflow: visible;
      position: relative;
    }
    
    .mask {
      overflow: hidden;
      height: 320px;
    }
    
    .slider ul {
      margin: 0;
      padding: 0;
      position: relative;
    }
    
    .slider li {
      width: 680px;
      height: 320px;
      position: absolute;
      right: -325px;
      list-style: none;
    }
    
    .slider .quote {
      font-size: 40px;
      font-style: italic;
      text-align: center;
    }
    
    .slider li.anim1 {
      animation: cycle 12s linear infinite;
    }
    
    .slider li.anim2 {
      animation: cycle2 12s linear infinite;
    }
    
    .slider li.anim3 {
      animation: cycle3 12s linear infinite;
    }
    
    .slider li.anim4 {
      animation: cycle4 12s linear infinite;
    }
    
    @keyframes cycle {
      0% {
        right: -325px;
        opacity: 0;
        z-index: -1;
      }
      4.2% {
        right: 0px;
        opacity: 1;
        z-index: 0;
      }
      20.8% {
        right: 0px;
        opacity: 1;
      }
      25% {
        right: 325px;
        opacity: 0;
        z-index: -1;
      }
      100% {
        right: -325px;
        opacity: 0;
      }
    }
    
    @keyframes cycle2 {
      0% {
        right: -325px;
        opacity: 0;
      }
      25% {
        right: -325px;
        opacity: 0;
      }
      29.2% {
        right: 0px;
        opacity: 1;
      }
      45.8% {
        right: 0px;
        opacity: 1;
      }
      50% {
        right: 325px;
        opacity: 0;
        z-index: -1;
      }
      100% {
        right: -325px;
        opacity: 0;
        z-index: -1;
      }
    }
    
    @keyframes cycle3 {
      0% {
        right: -325px;
        opacity: 0;
      }
      50% {
        right: -325px;
        opacity: 0;
      }
      54.2% {
        right: 0px;
        opacity: 1;
      }
      70.8% {
        right: 0px;
        opacity: 1;
      }
      75% {
        right: 325px;
        opacity: 0;
        z-index: -1;
      }
      100% {
        right: -325px;
        opacity: 0;
        z-index: -1;
      }
    }
    
    @keyframes cycle4 {
      0% {
        right: -325px;
        opacity: 0;
      }
      74.99% {
        right: -325px;
        opacity: 0;
      }
      79.2% {
        right: 0px;
        opacity: 1;
      }
      95.8% {
        right: 0px;
        opacity: 1;
      }
      100% {
        right: 325px;
        opacity: 0;
        z-index: -1;
      }
    }
    <div class="content-slider">
      <div class="slider">
        <div class="mask">
          <ul>
    
            <li class="anim1">
              <div class="quote"> Service to 200+ countries</div>
            </li>
            <li class="anim2">
              <div class="quote">Same day delivery services</div>
            </li>
            <li class="anim3">
              <div class="quote">Easy booking tools.</div>
            </li>
            <li class="anim4">
              <div class="quote">Rated great.</div>
            </li>
    
    
          </ul>
        </div>
      </div>
    </div>