CSS animation using translateX instead of margin-left, is it possible?

Issue

Recently I ran into the video demonstrating difference between margin and transform animations.
Unfortunately I can’t remember video title or link. but basically it claimed that using transform:translateX() was way smoother than margin-left, especially on throttling mode.

I made an automatic slideshow with margin-left, and I’m trying to rewrite the animation using translateX, couldn’t figure it out yet.
Any help will be appreciated.

body {
  margin: 0;
}

#slides {
  display: flex;
  overflow: hidden;
  height: 100vh;
  width: 100vw;
  margin: 0;
}

#slidewrapper {
  width: calc(6 * 100vw);
  /* you need to use calc for math */
  animation: slide 26s ease infinite;
}

.slide {
  /* float: left; <- unnecessary */
  height: 100vh;
  width: 100vw;
}

.landingphoto {
  height: 100vh;
  width: 100vw;
  object-fit: cover;
}

@keyframes slide {
  20% {
    margin-left: 0;
  }
  30% {
    margin-left: -100%;
  }
  50% {
    margin-left: -100%;
  }
  60% {
    margin-left: -200%;
  }
  70% {
    margin-left: -200%;
  }
  80% {
    margin-left: -300%;
  }
  90% {
    margin-left: -300%;
  }
}
<div id="slides">
  <div id="slidewrapper"></div>
  <div class="slide">
    <img src="https://source.unsplash.com/ULmaQh9Gvbg/1600x900" class="landingphoto">
  </div>
  <div class="slide">
    <img src="https://source.unsplash.com/ggZuL3BTSJU/1600x900" class="landingphoto">
  </div>
  <div class="slide">
    <img src="https://source.unsplash.com/yXpA_eCbtzI/1600x900" class="landingphoto">
  </div>
  <div class="slide">
    <img src="https://source.unsplash.com/RyRpq9SUwAU/1600x900" class="landingphoto">
  </div>
  <div class="slide">
    <img src="https://source.unsplash.com/BeOW_PJjA0w/1600x900" class="landingphoto">
  </div>
</div>

Solution

  • Don’t use IDs, components are meant to be reusable. Use only Classes.
  • Speaking or reusability, don’t hardcode animation in CSS. If you add only one image or remove one, you’ll find yourself in need to painfully modify the CSS to adjust for the problem. Use JavaScript instead (in combination with CSS transform)
// Carousel (slides):

const carousel = (elCarousel) => {
  
  const timePause = 4000;
  const timeAnim = 1000;
  
  const elsSlides = elCarousel.children;
  const tot = elsSlides.length;
  let itv;
  let c = 0; // current slide index
  
  elCarousel.style.transition = `transform ${timeAnim}ms`;
  
  const anim = () => { elCarousel.style.transform = `translateX(${-c * 100}%)`; };
  const play = () => { itv = setInterval(next, timePause); };
  const stop = () => { clearInterval(itv); };
  const next = () => { c += 1;c %= tot; anim(); };
  
  play();
  
};

// Apply carousel to desired elements:
document.querySelectorAll(".slidesWrapper").forEach(carousel);
/*QuickReset*/ * {margin:0; box-sizing: border-box;}

.slides {
  overflow: hidden;
}
.slidesWrapper {
  display: flex;
}
.slide {
  position: relative;
  flex: 0 0 100%;
  min-height: 200px;
}
.slide img {
  position: absolute;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
<div class="slides">
  <div class="slidesWrapper">
    <div class="slide">
      <img src="https://source.unsplash.com/ULmaQh9Gvbg/1600x900" class="landingphoto">
    </div>
    <div class="slide">
      <img src="https://source.unsplash.com/ggZuL3BTSJU/1600x900" class="landingphoto">
    </div>
    <div class="slide">
      <img src="https://source.unsplash.com/yXpA_eCbtzI/1600x900" class="landingphoto">
    </div>
    <div class="slide">
      <img src="https://source.unsplash.com/RyRpq9SUwAU/1600x900" class="landingphoto">
    </div>
    <div class="slide">
      <img src="https://source.unsplash.com/BeOW_PJjA0w/1600x900" class="landingphoto">
    </div>
  </div>
</div>

You can have as many carousels as you want!

<div class="slides">
  <div class="slidesWrapper">
    <div class="slide">
      <img src="https://source.unsplash.com/RyRpq9SUwAU/1600x900" class="landingphoto">
    </div>
    <div class="slide">
      <img src="https://source.unsplash.com/yXpA_eCbtzI/1600x900" class="landingphoto">
    </div>
    <div class="slide">
      <img src="https://source.unsplash.com/BeOW_PJjA0w/1600x900" class="landingphoto">
    </div>
  </div>
</div>

PS: if you want to pause the animation on mouseenter and restart the animation on mouseleave simply add this two lines:

elCarousel.addEventListener("pointerenter", stop);
elCarousel.addEventListener("pointerleave", play);

Answered By – Roko C. Buljan

Answer Checked By – Dawn Plyler (AngularFixing Volunteer)

Leave a Reply

Your email address will not be published.