Blog / CSS/JS

Scroll-driven animations : le guide complet

Maitrisez les animations declenchees au scroll pour creer des experiences web immersives. De l'Intersection Observer au scroll-timeline CSS natif, decouvrez 5 techniques essentielles.

Introduction

Les animations declenchees au scroll sont devenues incontournables pour creer des experiences web memorables. Elles permettent de guider l'attention de l'utilisateur, de raconter une histoire visuelle et d'ajouter une dimension interactive a vos pages.

Dans ce guide complet, nous allons explorer 5 techniques essentielles pour implementer des scroll-driven animations, de la plus classique (Intersection Observer) a la plus moderne (scroll-timeline CSS). Chaque technique est accompagnee d'une demo interactive et du code complet.

💡
Regardez cette page !

La barre de progression en haut de page et le suivi de lecture dans le sommaire sont des exemples concrets de scroll-driven animations. Scrollez pour les voir en action !

1. Fade-in au scroll avec Intersection Observer

L'Intersection Observer API est la methode la plus fiable et performante pour detecter quand un element entre dans le viewport. Contrairement aux anciennes techniques basees sur scroll events, elle ne bloque pas le thread principal.

Demo interactive

Rapide

Animation fluide

Performant

Zero jank

Compatible

Tous navigateurs

fade-in-observer.js
// Configuration de l'observer
const observerOptions = {
  root: null,          // viewport par defaut
  rootMargin: '0px',  // marge autour du viewport
  threshold: 0.1       // 10% visible pour declencher
};

// Callback quand un element entre/sort du viewport
const handleIntersect = (entries, observer) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      // Element visible : ajouter la classe
      entry.target.classList.add('visible');

      // Optionnel : arreter d'observer apres animation
      observer.unobserve(entry.target);
    }
  });
};

// Creer l'observer
const observer = new IntersectionObserver(handleIntersect, observerOptions);

// Observer tous les elements avec [data-animate]
document.querySelectorAll('[data-animate]').forEach(el => {
  observer.observe(el);
});
fade-in-styles.css
/* Etat initial : invisible et decale vers le bas */
.fade-card {
  opacity: 0;
  transform: translateY(30px);
  transition: all 0.6s cubic-bezier(0.4, 0, 0.2, 1);
}

/* Etat final : visible et a sa place */
.fade-card.visible {
  opacity: 1;
  transform: translateY(0);
}

/* Delai en cascade pour effet stagger */
.fade-card:nth-child(2) { transition-delay: 0.1s; }
.fade-card:nth-child(3) { transition-delay: 0.2s; }
.fade-card:nth-child(4) { transition-delay: 0.3s; }

Parametres cles de l'Intersection Observer

  • root : L'element parent qui sert de viewport (null = viewport du navigateur)
  • rootMargin : Marge autour du root (ex: "-100px" pour declencher 100px avant)
  • threshold : Pourcentage de visibilite requis (0.1 = 10%, 1 = 100%)

2. Effet Parallax

L'effet parallax cree une illusion de profondeur en faisant bouger differentes couches a des vitesses differentes lors du scroll. C'est un classique du web design moderne.

Scrollez pour voir l'effet
Parallax
parallax.js
// Elements avec differentes vitesses de parallax
const layers = [
  { element: document.querySelector('.parallax-stars'), speed: 0.2 },
  { element: document.querySelector('.parallax-moon'), speed: 0.3 },
  { element: document.querySelector('.mountain-1'), speed: 0.5 },
  { element: document.querySelector('.mountain-2'), speed: 0.7 },
];

// Fonction optimisee avec requestAnimationFrame
let ticking = false;

function updateParallax() {
  const scrollY = window.scrollY;

  layers.forEach(layer => {
    const yOffset = scrollY * layer.speed;
    layer.element.style.transform = `translateY(${yOffset}px)`;
  });

  ticking = false;
}

window.addEventListener('scroll', () => {
  if (!ticking) {
    window.requestAnimationFrame(updateParallax);
    ticking = true;
  }
});
⚠️
Performance critique

Utilisez toujours requestAnimationFrame pour les animations liees au scroll. Sans cette optimisation, vous risquez des saccades (jank) qui degradent l'experience utilisateur.

3. Progress bar de lecture

La barre de progression de lecture est un excellent indicateur visuel pour les articles longs. Elle montre a l'utilisateur ou il en est dans sa lecture.

Simulation
0%
Progression de lecture
reading-progress.js
const progressBar = document.querySelector('.reading-progress');
const article = document.querySelector('.article-content');

function updateProgress() {
  // Position de l'article
  const articleTop = article.getBoundingClientRect().top + window.scrollY;
  const articleHeight = article.offsetHeight;
  const windowHeight = window.innerHeight;

  // Calcul du pourcentage
  const scrolled = window.scrollY - articleTop + windowHeight;
  const total = articleHeight + windowHeight;
  const progress = Math.min(Math.max(scrolled / total, 0), 1);

  // Mise a jour de la barre
  progressBar.style.width = `${progress * 100}%`;
}

// Ecouter le scroll avec throttling
let rafId = null;
window.addEventListener('scroll', () => {
  if (rafId) return;
  rafId = requestAnimationFrame(() => {
    updateProgress();
    rafId = null;
  });
});
reading-progress.css
.reading-progress {
  position: fixed;
  top: 0;
  left: 0;
  width: 0%;
  height: 3px;
  background: linear-gradient(
    90deg,
    #6366f1,
    #8b5cf6,
    #d946ef
  );
  z-index: 9999;
  transition: width 0.1s ease-out;
}

4. Reveal animations (slide, scale)

Les reveal animations permettent de faire apparaitre les elements de differentes manieres : depuis la gauche, la droite, avec un effet de zoom, ou meme avec une rotation. Voici un exemple avec plusieurs variantes.

Demo interactive

Slide Left

Entre depuis la gauche

Slide Right

Entre depuis la droite

Scale

Zoom depuis le centre

Rotate

Rotation + scale

reveal-animations.css
/* Slide depuis la gauche */
.reveal-slide-left {
  opacity: 0;
  transform: translateX(-50px);
  transition: all 0.6s cubic-bezier(0.4, 0, 0.2, 1);
}

/* Slide depuis la droite */
.reveal-slide-right {
  opacity: 0;
  transform: translateX(50px);
  transition: all 0.6s cubic-bezier(0.4, 0, 0.2, 1);
}

/* Scale depuis le centre */
.reveal-scale {
  opacity: 0;
  transform: scale(0.8);
  transition: all 0.6s cubic-bezier(0.4, 0, 0.2, 1);
}

/* Rotation + scale */
.reveal-rotate {
  opacity: 0;
  transform: rotate(-10deg) scale(0.9);
  transition: all 0.6s cubic-bezier(0.4, 0, 0.2, 1);
}

/* Etat visible commun */
.reveal-slide-left.visible,
.reveal-slide-right.visible,
.reveal-scale.visible,
.reveal-rotate.visible {
  opacity: 1;
  transform: translateX(0) scale(1) rotate(0);
}

Animation en cascade (stagger)

Pour creer un effet de cascade elegant, utilisez transition-delay avec une valeur incrementale :

stagger-delay.js
// Ajouter un delai incrementiel a chaque element
const items = document.querySelectorAll('[data-animate="reveal"]');

items.forEach((item, index) => {
  item.style.transitionDelay = `${index * 0.1}s`;
});

5. Scroll-timeline CSS natif

La specification CSS Scroll-driven Animations permet de lier des animations directement a la progression du scroll, sans JavaScript. C'est la methode la plus performante car elle s'execute entierement sur le GPU.

CSS natif (Chrome 115+)

Animation liee au scroll

Scrollez la page pour voir la transformation

Chrome 115+ / Edge 115+
scroll-timeline.css
/* Animation keyframes classique */
@keyframes scrollReveal {
  from {
    opacity: 0;
    transform: translateY(100px) scale(0.8);
  }
  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

.scroll-animated-element {
  /* Lier l'animation au scroll de la page */
  animation: scrollReveal linear;
  animation-timeline: scroll();

  /* Controler quand l'animation se joue */
  animation-range: entry 0% cover 50%;
}

Options de animation-timeline

  • scroll() : Lie a la timeline de scroll du document
  • scroll(root) : Lie au scroll du document racine
  • scroll(nearest) : Lie au conteneur scrollable le plus proche
  • view() : Lie a la visibilite de l'element dans le viewport

Options de animation-range

  • entry : Quand l'element entre dans le viewport
  • exit : Quand l'element sort du viewport
  • cover : Quand l'element couvre le viewport
  • contain : Quand l'element est entierement visible
🔮
Compatibilite navigateurs

Scroll-timeline est supporte dans Chrome 115+ et Edge 115+. Pour une compatibilite plus large, utilisez l'Intersection Observer avec un fallback.

Bonnes pratiques et accessibilite

Performance

  • Utilisez transform et opacity : Ces proprietes sont composites et animees sur le GPU
  • Evitez d'animer width, height, top, left : Elles declenchent un reflow couteux
  • Throttling avec requestAnimationFrame : Essentiel pour les animations liees au scroll
  • will-change avec parcimonie : Utile mais consomme de la memoire GPU

Accessibilite

Respectez toujours les preferences utilisateur concernant les animations :

accessibility.css
/* Desactiver les animations si l'utilisateur le demande */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }

  /* Afficher directement les elements animes */
  .fade-card,
  .reveal-item {
    opacity: 1 !important;
    transform: none !important;
  }
}
check-motion-preference.js
// Verifier la preference utilisateur en JavaScript
const prefersReducedMotion = window.matchMedia(
  '(prefers-reduced-motion: reduce)'
);

if (prefersReducedMotion.matches) {
  // Desactiver les animations JavaScript
  console.log('Animations reduites');
}

// Ecouter les changements de preference
prefersReducedMotion.addEventListener('change', () => {
  // Reactiver/desactiver dynamiquement
});

Tableau comparatif des techniques

Technique Performance Compatibilite Cas d'usage
Intersection Observer Excellente 97%+ Reveal, lazy loading
Scroll event + rAF Bonne 100% Parallax, progress bar
CSS scroll-timeline Optimale ~75% Animations complexes

Conclusion

Les scroll-driven animations sont un outil puissant pour creer des experiences web immersives. Avec les 5 techniques presentees dans ce guide, vous avez tout ce qu'il faut pour implementer des animations performantes et accessibles.

Retenez ces points essentiels :

  • Intersection Observer pour les animations de reveal simples
  • requestAnimationFrame pour le parallax et les progress bars
  • CSS scroll-timeline pour les animations complexes (avec fallback)
  • Toujours respecter prefers-reduced-motion
🚀
Explorez notre bibliotheque

Retrouvez des dizaines d'effets scroll prets a l'emploi dans notre bibliotheque d'effets, avec code copiable et personnalisable.