Introduction
Le scrollytelling est une technique de narration visuelle qui utilise le scroll pour reveler progressivement une histoire ou des informations. Combinee avec la propriete CSS position: sticky, elle permet de creer des experiences web immersives dignes des plus grands sites editoriaux comme le New York Times ou Bloomberg.
Dans ce guide complet, nous allons explorer en profondeur les techniques fondamentales et avancees pour maitriser ces effets. Vous apprendrez a utiliser position sticky, l'Intersection Observer API, et meme les nouvelles scroll-driven animations natives de CSS.
Des etudes montrent que les contenus interactifs avec scrollytelling ont un taux d'engagement 3x superieur aux contenus statiques. C'est particulierement efficace pour la visualisation de donnees et les articles longs.
Position sticky expliquee
La propriete position: sticky est le fondement de nombreux effets de scrollytelling. Elle permet a un element de basculer entre un comportement relative et fixed en fonction de la position de scroll.
Le fonctionnement de base
Un element sticky commence par se comporter comme un element positionne relativement. Puis, lorsqu'il atteint un seuil defini (par exemple top: 0), il devient "colle" a cette position comme un element fixed, jusqu'a ce que son conteneur parent sorte de la vue.
Faites defiler pour voir l'effet sticky en action. L'element violet reste colle en haut du conteneur pendant que vous scrollez.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Continuez a scroller pour voir l'element sticky suivre le defilement jusqu'a la fin du conteneur.
/* Conteneur qui definit la zone de scroll */
.sticky-container {
position: relative;
height: 300vh; /* Grande hauteur pour le scroll */
}
/* Element qui reste colle */
.sticky-element {
position: sticky;
top: 20px; /* Distance depuis le haut */
background: linear-gradient(135deg, #6366f1, #8b5cf6);
padding: 24px 32px;
border-radius: 12px;
}
Points importants
- Le parent doit avoir une hauteur : sticky ne fonctionne que si le conteneur parent a suffisamment de hauteur pour permettre le scroll
- Pas de overflow: hidden sur les ancetres : cette propriete peut casser le comportement sticky
- Specifiez top, bottom, left ou right : au moins une de ces proprietes doit etre definie
- Fonctionne avec tous les navigateurs modernes : support a 95%+ sans prefixe
Si votre element sticky ne fonctionne pas, verifiez que vous n'avez pas overflow: hidden, overflow: auto ou overflow: scroll sur un element parent entre le sticky et le viewport.
Scrollytelling avec Intersection Observer
L'API Intersection Observer permet de detecter quand un element entre ou sort du viewport (ou d'un autre element). C'est l'outil ideal pour declencher des animations ou des changements d'etat lors du scroll.
Demo interactive
Scrollez dans la zone de droite pour voir le visuel changer en fonction de l'etape active :
Etape 1 : Introduction
Le cercle commence dans sa forme initiale, avec un gradient violet classique.
Etape 2 : Transformation
Le cercle s'agrandit et prend une forme arrondie carree avec un nouveau gradient.
Etape 3 : Rotation
L'element pivote et change de couleur vers des tons cyan-vert.
Etape 4 : Conclusion
Retour a une forme circulaire avec des couleurs chaudes orange-rouge.
// Selection des elements
const steps = document.querySelectorAll('.scroll-step');
const visual = document.querySelector('.visual-circle');
// Configuration de l'observer
const observerOptions = {
root: document.querySelector('.scrollytelling-steps'),
rootMargin: '-30% 0px -30% 0px', // Zone de detection
threshold: 0
};
// Callback de l'observer
const observerCallback = (entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
// Recuperer le numero de l'etape
const step = entry.target.dataset.step;
// Mettre a jour le visuel
visual.setAttribute('data-step', step);
visual.textContent = step;
// Mettre a jour les classes actives
steps.forEach(s => s.classList.remove('active'));
entry.target.classList.add('active');
}
});
};
// Creation et activation de l'observer
const observer = new IntersectionObserver(observerCallback, observerOptions);
steps.forEach(step => observer.observe(step));
Comprendre les options
- root : l'element de reference (null = viewport)
- rootMargin : marges pour etendre ou reduire la zone de detection
- threshold : pourcentage de visibilite pour declencher le callback (0 a 1)
Scroll-timeline CSS natif
Les scroll-driven animations sont une nouvelle specification CSS qui permet de lier directement des animations au scroll, sans JavaScript ! C'est la methode la plus performante car tout se passe sur le GPU.
En 2025, scroll-timeline est supporte par Chrome, Edge et Opera. Firefox et Safari sont en cours d'implementation. Utilisez une detection de fonctionnalite pour le fallback.
/* Definition de la timeline de scroll */
@scroll-timeline scroll-progress {
source: auto; /* Element scrollable (auto = ancetre) */
orientation: vertical;
scroll-offsets: 0%, 100%;
}
/* Animation liee au scroll */
.progress-bar {
animation: fillProgress linear;
animation-timeline: scroll-progress;
}
@keyframes fillProgress {
from { width: 0%; }
to { width: 100%; }
}
Nouvelle syntaxe simplifiee
La specification a evolue vers une syntaxe plus simple avec animation-timeline: scroll() :
/* Barre de progression liee au scroll de la page */
.reading-progress {
position: fixed;
top: 0;
left: 0;
height: 4px;
background: linear-gradient(90deg, #6366f1, #8b5cf6);
transform-origin: left;
/* Animation liee au scroll */
animation: scaleProgress linear forwards;
animation-timeline: scroll(root);
}
@keyframes scaleProgress {
from { transform: scaleX(0); }
to { transform: scaleX(1); }
}
/* Animation liee a la visibilite d'un element (view timeline) */
.fade-in-element {
animation: fadeIn linear forwards;
animation-timeline: view();
animation-range: entry 0% cover 40%;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(50px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
Exemples pratiques avances
Voyons maintenant des cas d'usage concrets et plus elabores.
1. Indicateur de progression de lecture
Une barre qui montre ou vous en etes dans la lecture de l'article :
// Indicateur de progression de lecture
function initReadingProgress() {
const progressBar = document.querySelector('.progress-fill');
const article = document.querySelector('article');
function updateProgress() {
// Calculer la position de scroll
const scrollTop = window.scrollY;
const docHeight = article.offsetHeight - window.innerHeight;
const progress = (scrollTop / docHeight) * 100;
// Limiter entre 0 et 100
const clampedProgress = Math.min(100, Math.max(0, progress));
// Mettre a jour la largeur
progressBar.style.width = clampedProgress + '%';
}
// Ecouter le scroll avec throttling
let ticking = false;
window.addEventListener('scroll', () => {
if (!ticking) {
requestAnimationFrame(() => {
updateProgress();
ticking = false;
});
ticking = true;
}
});
}
2. Timeline verticale animee
Un composant de timeline qui s'anime a mesure que l'utilisateur scrolle :
Phase 1 : Recherche
Analyse des besoins utilisateurs
Phase 2 : Design
Creation des maquettes UI/UX
Phase 3 : Developpement
Implementation technique
Phase 4 : Lancement
Deploiement en production
<!-- Structure HTML de la timeline -->
<div class="timeline-track">
<div class="timeline-item">
<div class="timeline-dot"></div>
<div class="timeline-content">
<h4>Titre de l'etape</h4>
<p>Description de l'etape</p>
</div>
</div>
<!-- Autres items... -->
</div>
<style>
.timeline-track {
position: relative;
padding-left: 40px;
}
/* Ligne verticale */
.timeline-track::before {
content: '';
position: absolute;
left: 12px;
top: 0;
bottom: 0;
width: 2px;
background: rgba(255,255,255,0.1);
}
.timeline-dot {
position: absolute;
left: -34px;
width: 16px;
height: 16px;
border-radius: 50%;
background: #12121a;
border: 2px solid rgba(255,255,255,0.1);
transition: all 0.3s ease;
}
/* Etat actif */
.timeline-item.active .timeline-dot {
background: #6366f1;
border-color: #6366f1;
box-shadow: 0 0 20px rgba(99,102,241,0.5);
}
</style>
3. Parallaxe avec sticky
Combiner sticky avec des transformations pour creer un effet de parallaxe :
/* Section avec parallaxe sticky */
.parallax-section {
height: 200vh;
position: relative;
}
.parallax-background {
position: sticky;
top: 0;
height: 100vh;
overflow: hidden;
}
.parallax-image {
width: 100%;
height: 120%;
object-fit: cover;
will-change: transform;
}
.parallax-content {
position: absolute;
bottom: 0;
left: 0;
right: 0;
padding: 100vh 20px 50px;
background: linear-gradient(
to bottom,
transparent,
rgba(10,10,15,0.8) 30%,
#0a0a0f
);
}
Bonnes pratiques
Pour creer des experiences de scrollytelling performantes et accessibles, suivez ces recommandations :
Performance
- Utilisez requestAnimationFrame pour les animations liees au scroll en JavaScript
- Privilegiez transform et opacity pour les animations (proprietes qui ne declenchent pas de reflow)
- Activez will-change avec parcimonie sur les elements animes
- Preferez scroll-timeline CSS quand c'est possible (rendu GPU)
- Limitez le nombre d'observers : un seul observer peut surveiller plusieurs elements
// Optimisation avec requestAnimationFrame
let rafId = null;
let lastScrollY = 0;
function onScroll() {
lastScrollY = window.scrollY;
if (!rafId) {
rafId = requestAnimationFrame(updateAnimations);
}
}
function updateAnimations() {
// Vos animations ici
// Utilisez transform au lieu de top/left
element.style.transform = `translateY(${lastScrollY * 0.5}px)`;
rafId = null;
}
window.addEventListener('scroll', onScroll, { passive: true });
Accessibilite
- Respectez prefers-reduced-motion : desactivez ou reduisez les animations
- Le contenu doit etre lisible sans JS : progressive enhancement
- Testez au clavier : le focus doit suivre le contenu visible
- Utilisez aria-live pour les changements dynamiques importants
/* Desactiver les animations pour les utilisateurs sensibles */
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
/* Les elements sticky restent fonctionnels */
.sticky-element {
position: sticky; /* conserve */
}
}
UX et Design
- Donnez des indices visuels : l'utilisateur doit comprendre qu'il peut scroller
- Evitez le scroll jacking : ne modifiez pas la vitesse de scroll native
- Testez sur mobile : le comportement peut differer significativement
- Prevoyez des fallbacks : le contenu doit etre accessible sans les effets
Utilisez le DevTools pour profiler vos animations. Dans Chrome, ouvrez Performance > Record pendant que vous scrollez, puis analysez les "Frames" pour detecter les chutes de FPS.
Conclusion
Le scrollytelling et les sections sticky sont des outils puissants pour creer des experiences web memorables. En combinant position: sticky, l'Intersection Observer et les nouvelles scroll-driven animations, vous disposez de tout l'arsenal necessaire pour rivaliser avec les meilleurs sites editoriaux.
Les points cles a retenir :
- position: sticky est la base de nombreux effets de scroll
- Intersection Observer permet de declencher des actions sans impact sur les performances
- scroll-timeline CSS est l'avenir des animations liees au scroll
- La performance et l'accessibilite doivent toujours etre prioritaires
N'hesitez pas a experimenter et a combiner ces techniques. Les possibilites sont infinies !
Decouvrez nos templates de scrollytelling prets a l'emploi dans la bibliotheque Effects.lab, avec des effets sophistiques et du code optimise.