Unlike traditional CSS animations, interactive animations require more than just listening for click events and adding CSS classes on elements we want to animate.

Instead, when we are building an advanced interactive animation, we need to consider a wider array of events and perform different animations depending on user intent.

Let's illustrate this by creating three slider animations, each slightly more sophisticated than the one before. As we do this, we can see how reading more data from interactions can result in more responsive and interesting animations.

Detect swipe direction only

Our first example will detect swipe direction and animate the slide left or right. We will use a very popular gesture library called hammer.js to detect mouse and touch swiping simultaneously.

const slide = document.querySelector(".slide");
const container = document.querySelector(".container");
const listener = new Hammer(container);

listener.on("panend", function(e) {
  // panend = [touchend, mouseup]

  slide.style.transition = "transform 0.3s ease-in-out";

  if (e.deltaX > 0) {
    // swipe right
    slide.style.transform = `translateX(${container.offsetWidth}px)`;
  } else {
    // swipe left
    slide.style.transform = `translateX(${-container.offsetWidth}px)`;
  }
});

Notice how the animation is triggered at the end of the swipe event, creating a delay between the moment our gesture was initiated and the animation start.

Detect swipe and drag

In order to improve our animation, we need to start dragging the slide at the very beginning of the user interaction. Then, depending on whether the user has completed or cancelled the swipe, we will transition the slide all the way through or back to its initial position:

if (
  // swiped more than halfway ?
  Math.abs(e.deltaX) > container.offsetWidth / 2 ||
  // swiped fast, i.e more than 0.5px / ms?
  Math.abs(e.velocityX) > 0.5
) {
  // complete swipe
} else {
  // cancel swipe
}

Different animation for cancelled swipe

To take our animation even further, we could use a different effect for the cancelled swipe. A bounce effect would be just great - it would create a sense of elasticity as in real-world physics.

To create the bounce effect, we would need something more advanced than simply assigning a new style.transtion property on the slide object, as we did in the previous examples. Instead, we would use a custom easing along with requestAnimationFrame to perform the animation. You can read more about requestAnimationFrame here, but the main idea can be seen below:

const bounceEasing = () =>
  -1 * Math.pow(4, -8 * t) * Math.sin(((t * 6 - 1) * (2 * Math.PI)) / 2) + 1;

const bounceSlide = () => {
  const distance = 300; // px
  const duration = 300; // ms
  const start = performance.now();

  const tick = () => {
    const elapsed = performance.now() - start;
    const progress = elapsed / duration;
    const translateX = bounceEasing(progress) * distance;

    slide.style.transform = `translateX(${translateX}px)`;

    if (progress < 1) {
      requestAnimationFrame(tick);
    }
  };

  requestAnimationFrame(tick);
};

Of course, if this technique seems tricky, you could always use an animation library like anime.js or gsap, both of which have advanced easing functions as well as many other functionalities.

No matter what you decide to use though, it is good to remember that interactive animations are not just about moving objects around, but also about the way in which the user has intended to move them.