Image Trail Effect

Share

This effect is widely used in modern web design: when the user moves their mouse, a succession of images appears and disappears with a smooth animation.

Add the HTML Structure in Elementor

  1. In Elementor, add an HTML Widget to your page.
  2. Paste this code:
<div class="items"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/gsap.min.js"></script>

<script>
   const imagePaths = [
      "https://images.pexels.com/photos/18131871/pexels-photo-18131871.jpeg?w=300&auto=compress&cs=tinysrgb",
      "https://images.pexels.com/photos/18398708/pexels-photo-18398708.jpeg?w=300&auto=compress&cs=tinysrgb",
      "https://images.pexels.com/photos/18131896/pexels-photo-18131896.jpeg?w=300&auto=compress&cs=tinysrgb",
      "https://images.pexels.com/photos/18398385/pexels-photo-18398385.jpeg?w=300&auto=compress&cs=tinysrgb",
      "https://images.pexels.com/photos/18398430/pexels-photo-18398430.jpeg?w=300&auto=compress&cs=tinysrgb"
      // ajoute ou enlève des images ici
   ];

   document.addEventListener("DOMContentLoaded", function () {
      const container = document.querySelector(".items");
      let imageIndex = 0;

      let lastX = null;
      let lastY = null;
      const minDistance = 100; // Distance minimale avant apparition d’une nouvelle image

      function getDistance(x1, y1, x2, y2) {
         const dx = x2 - x1;
         const dy = y2 - y1;
         return Math.sqrt(dx * dx + dy * dy);
      }

      function addNewItem(x, y, dx, dy) {
         const newItem = document.createElement("div");
         newItem.className = "item";
         newItem.style.position = "absolute";
         newItem.style.left = `${x - 150}px`;
         newItem.style.top = `${y - 150}px`;
         newItem.style.width = "300px";
         newItem.style.height = "300px"; // définit la taille de l'image
         newItem.style.pointerEvents = "none";

         const img = document.createElement("img");
         img.src = imagePaths[imageIndex];
         img.style.width = "100%";
         img.style.height = "100%";
         img.style.objectFit = "contain";
         newItem.appendChild(img);

         container.appendChild(newItem);

         imageIndex = (imageIndex + 1) % imagePaths.length;

         const randomRotation = gsap.utils.random(0, 0);

         // Normalisation direction
         const length = Math.sqrt(dx * dx + dy * dy) || 1;
         const dirX = (dx / length) * 80; // Direction et amplitude de l’entrée
         const dirY = (dy / length) * 80; // Direction et amplitude de l’entrée

         // Animation GSAP
         gsap.timeline()
            .fromTo(newItem,
               { scale: 1, opacity: 1, rotation: randomRotation, x: -dirX, y: -dirY },
               { scale: 1, opacity: 1, x: 0, y: 0, duration: 0.4, ease: "power2.out" } 
            )
            .to(newItem,
               { 
                 scale: 0.3, opacity: 0, duration: 1, ease: "power2.out", delay: 0.05, 
                 onComplete: () => newItem.remove() 
               } 
            );
      }

      container.addEventListener("mousemove", function (event) {
         if (lastX === null || lastY === null) {
            lastX = event.pageX;
            lastY = event.pageY;
            return;
         }

         const dx = event.pageX - lastX;
         const dy = event.pageY - lastY;
         const distance = getDistance(lastX, lastY, event.pageX, event.pageY);

         if (distance > minDistance) {
            addNewItem(event.pageX, event.pageY, dx, dy);
            lastX = event.pageX;
            lastY = event.pageY;
         }
      });
   });
</script>

Add the CSS in Elementor

Still in the HTML widget, go to Advanced and then Custom CSS, add:

.items { 
  position: fixed; 
  top: 0; 
  left: 0; 
  width: 100vw; 
  height: 100vh; 
  will-change: transform, opacity; 
  z-index: 999; /* passe au-dessus du contenu */
} 

.item { 
  position: absolute; 
  width: 450px; 
  height: 600px; 
  overflow: hidden; 
} 

.item img { 
  width: 150%; 
  height: 250%; 
  object-fit: cover; 
}

Customize the Animation

You can adapt the effect by modifying these key lines of the script:

Minimum distance before a new image appears const minDistance = 100; → Lower = more images, higher = fewer images.

Direction and amplitude of entry const dirX = (dx / length) * 80; const dirY = (dy / length) * 80; → Change 80 to increase/decrease the “trajectory” effect.

Appearance duration duration: 0.4 → Lower = faster, higher = slower.

Disappearance animation
Currently: scale: 0.3, opacity: 0, duration: 1, ease: "power2.out"
Suggested variant for a downward fall effect:

y: window.innerHeight + 300, opacity: 0, scale: 0.3, duration: 1.2, ease: "power2.in", onComplete: () => item.remove()

Practical Tips

  • Image compression: optimize images with TinyPNG or Squoosh.
  • Image size: avoid overly heavy originals (200–400px max for this effect).
  • Mobile performance: disable this effect on mobile if smoothness is not optimal.
Category
Compatible
WordPress, Elementor
Updated
17 Sep 2025

Built with Elementor

Host, create, and grow your dream website with the leading platform for WordPress.

Inspire your Elementor projects with 1 animation per week.

Thank you for subscribing!