Search code examples
cssslidercss-animationstransformtranslate

CSS Slider Using `transform: translateX` To Cycle Through Images


Is it possible to have a CSS slider cycle through two images when animating them with the translateX transform property?

I'm facing a couple of issues:

  1. I can't seem to get the second image to show even though it is in the HTML unless I use position: absolute and then the overflow: hidden doesn't work on the parent?

  2. How do I reset the first image to go back to the beginning to start it all again?

Note: in the animation shorthand, the animation lasts for 2.5s and there is an initial delay of 3s.

I only want to do with this with the translateX property because I want the 60FPS smoothness (it will be done with translate3d when completed, but to make the code easier to read I've used translateX). I don't wish to animate margin: left or the left property etc.

Any help would be amazing.

Code is below or link to Codepen: https://codepen.io/anna_paul/pen/ZEJrvRp

body {
  position: relative;
  margin: 0;
  display: flex;
  justify-content: center;
}

.container {
  width: 500px;
  height: 333px;
  overflow: hidden;
}

.slider-wrapper {
  display: flex;
}

.image {
  display: block;
}

.hero-image-1 {
  transform: translateX(0);
  animation: slide-out-image-1 2.5s 3s cubic-bezier(0.54, 0.12, 0.44, 1)
    forwards;
}

@keyframes slide-out-image-1 {
  0% {
    transform: translateX(0);
  }
  100% {
    transform: translateX(-100%);
  }
}

.hero-image-2 {
  transform: translateX(100%);
  animation: slide-in-image-2 2.5s 3s cubic-bezier(0.54, 0.12, 0.44, 1) forwards;
}

@keyframes slide-in-image-2 {
  0% {
    transform: translateX(100%);
  }
  100% {
    transform: translateX(0);
  }
}
<div class="container">
  <div class="slider-wrapper">
    <picture>
      <img class="image hero-image-1" src="https://drive.google.com/uc?export=view&id=1l7cTX35wqd-4eYvFL8A5QLZ7LbOF9m4J">
    </picture>
    <picture>
      <img class="image hero-image-2" src="https://drive.google.com/uc?export=view&id=1iB9R1aoeYSmkPX9Ju3NNOZhKylOjCA0y">
    </picture>
  </div>
</div>


Solution

  • To create a slider loop you need to define animation points, when slider moving and stopping. In you case it look that


    2.5s + 3s +2.5s +3s = 11s or move + pause(out of container) + move + pause = totall.


    For the first image we need to animate out of container, then move to start position (out of container), waiting (second image animate), then animate to initial positio and pause.

    For the second image, we just show and then hide.

    body {
      height: 100vh;
      background-color: hsl(201, 27%, 10%);
      color: white;
      display: grid;
      place-items: center;
      position: relative;
    }
    
    :root {
      --animate: 2.5s;
      --pause: 3s;
      --totall-duration: calc(var(--animate) * 2 + var(--pause) * 2);
    }
    
    .container {
      width: 500px;
      height: 333px;
      overflow: hidden;
    }
    
    .slider-wrapper {
      width: 200%;
      display: flex;
      position: relative;
    }
    
    .image {
      display: flex;
      width: 100%;
      height: 100%;
    }
    
    .hero-image-1 {
      top: 0;
      left: 0;
      position: absolute;
      animation: slide-out-image-1 var(--totall-duration) 3s
        cubic-bezier(0.54, 0.12, 0.44, 1) infinite;
    }
    /* start + pause + start + pause = totall */
    /* 2.5s + 3s + 2.5s + 3s = 11s*/
    @keyframes slide-out-image-1 {
      0% {
        transform: translateX(0);
      }
      25% {
        transform: translateX(-100%);
      }
      25.0001% {
        transform: translateX(100%);
      }
      50% {
        transform: translateX(100%);
      }
      75% {
        transform: translateX(0%);
      }
      100% {
        transform: translateX(0%);
      }
    }
    
    .hero-image-2 {
      top: 0;
      right: 0;
      position: absolute;
      animation: slide-in-image-2 var(--totall-duration) 3s
        cubic-bezier(0.54, 0.12, 0.44, 1) infinite;
    }
    
    /* start + pause + start + pause = totall */
    /* 2.5s + 3s + 2.5s + 3s = 11s*/
    @keyframes slide-in-image-2 {
      0% {
        transform: translateX(0);
      }
      25% {
        transform: translateX(-100%);
      }
      50% {
        transform: translateX(-100%);
      }
      75% {
        transform: translateX(-200%);
      }
      100% {
        transform: translateX(-200%);
      }
    }
    <div class="container">
      <div class="slider-wrapper">
        <picture class="hero-image-1">
          <img class="image" src="https://drive.google.com/uc?export=view&id=1l7cTX35wqd-4eYvFL8A5QLZ7LbOF9m4J" />
        </picture>
        <picture class="hero-image-2">
          <img class="image" src="https://drive.google.com/uc?export=view&id=1iB9R1aoeYSmkPX9Ju3NNOZhKylOjCA0y" />
        </picture>
      </div>
    </div>