Débloquez des animations fluides et performantes basées sur le défilement en CSS pur. Ce guide couvre animation-timeline et animation-range pour un contrÎle précis.
CSS Animation Range : Une analyse approfondie du contrÎle des animations pilotées par le défilement
Depuis des annĂ©es, la crĂ©ation d'animations qui rĂ©agissent Ă la position de dĂ©filement de l'utilisateur est une pierre angulaire des expĂ©riences web engageantes. Des fondus subtils aux effets de parallaxe complexes, ces interactions donnent vie aux pages statiques. Cependant, elles ont traditionnellement eu un coĂ»t significatif : la dĂ©pendance Ă JavaScript. Les bibliothĂšques et les scripts personnalisĂ©s qui Ă©coutent les Ă©vĂ©nements de dĂ©filement peuvent ĂȘtre gourmands en performances, s'exĂ©cutant sur le thread principal et pouvant potentiellement entraĂźner des expĂ©riences utilisateur saccadĂ©es et peu rĂ©actives, en particulier sur les appareils moins puissants.
Entrez dans une nouvelle Ăšre de l'animation web. Les derniĂšres avancĂ©es en CSS rĂ©volutionnent la façon dont nous gĂ©rons ces interactions. La spĂ©cification Scroll-Driven Animations (Animations PilotĂ©es par le DĂ©filement) offre un moyen puissant, dĂ©claratif et trĂšs performant de lier les animations directement Ă la position d'une barre de dĂ©filement ou Ă la visibilitĂ© d'un Ă©lĂ©ment dans la fenĂȘtre d'affichage (viewport) â le tout sans une seule ligne de JavaScript.
Au cĆur de ce nouveau paradigme se trouvent deux propriĂ©tĂ©s clĂ©s : animation-timeline et animation-range. Alors que animation-timeline prĂ©pare le terrain en dĂ©finissant ce qui pilote l'animation (par exemple, la barre de dĂ©filement du document), c'est animation-range qui nous donne le contrĂŽle granulaire que nous avons toujours dĂ©sirĂ©. Elle nous permet de dĂ©finir les points de dĂ©part et de fin prĂ©cis d'une animation au sein de cette timeline.
Dans ce guide complet, nous explorerons le monde des animations CSS pilotées par le défilement avec un accent particulier sur animation-range. Nous aborderons :
- Les concepts fondamentaux des timelines de progression de défilement (Scroll) et de vue (View).
- Une analyse détaillée de la propriété
animation-rangeet de sa syntaxe. - Des exemples pratiques et concrets pour créer des barres de progression, des effets de révélation, et plus encore.
- Les meilleures pratiques en matiÚre de performance, d'accessibilité et de compatibilité avec les navigateurs.
Préparez-vous à débloquer des animations qui sont non seulement magnifiques mais aussi incroyablement efficaces, déplaçant la logique complexe du thread principal vers le thread du compositeur pour une fluidité garantie.
Comprendre les fondations : que sont les animations pilotées par le défilement ?
Avant de nous plonger dans animation-range, il est crucial de comprendre le systÚme dans lequel elle opÚre. Traditionnellement, les animations CSS sont liées à une timeline basée sur le temps. Lorsque vous définissez animation-duration: 3s;, l'animation progresse de 0 % à 100 % en trois secondes, pilotée par une horloge.
Les animations pilotĂ©es par le dĂ©filement changent fondamentalement cela. Elles introduisent le concept d'une timeline de progression (Progress Timeline), qui n'est pas pilotĂ©e par le temps, mais par la progression â soit la progression du dĂ©filement d'un conteneur, soit la progression de la visibilitĂ© d'un Ă©lĂ©ment lorsqu'il se dĂ©place dans la fenĂȘtre d'affichage.
Ce nouveau modĂšle offre trois avantages majeurs :
- Performance : Parce que ces animations peuvent ĂȘtre exĂ©cutĂ©es en dehors du thread principal sur le thread du compositeur du navigateur, elles n'entrent pas en compĂ©tition pour les ressources avec JavaScript, les opĂ©rations de mise en page ou de rendu. Le rĂ©sultat est une animation exceptionnellement fluide, exempte des saccades qui affectent souvent les Ă©couteurs de dĂ©filement basĂ©s sur JS.
- Simplicité : La syntaxe CSS est déclarative. Vous déclarez ce que vous voulez qu'il se passe, et le navigateur s'occupe des calculs complexes. Cela conduit souvent à un code plus propre et plus facile à maintenir par rapport au JavaScript impératif.
- Accessibilité : Les animations respectent par défaut les préférences de l'utilisateur comme
prefers-reduced-motion, ce qui facilite la création d'expériences inclusives.
Il existe deux principaux types de timelines de progression avec lesquels vous travaillerez :
- Timeline de progression de défilement (Scroll Progress Timeline) : Suit la position de défilement dans un conteneur de défilement (un "scroller"). La timeline représente toute la plage de défilement, du haut (0 %) jusqu'en bas (100 %).
- Timeline de progression de la vue (View Progress Timeline) : Suit la visibilitĂ© d'un Ă©lĂ©ment lorsqu'il traverse la fenĂȘtre d'affichage. La timeline reprĂ©sente le parcours de l'Ă©lĂ©ment depuis son entrĂ©e dans la fenĂȘtre d'affichage jusqu'Ă sa sortie complĂšte.
Le concept de base : la propriété `animation-timeline`
La premiÚre étape pour créer une animation pilotée par le défilement est de détacher une animation CSS standard de son horloge par défaut basée sur le temps et de l'attacher à une nouvelle timeline basée sur la progression. Cela se fait à l'aide de la propriété animation-timeline.
Elle accepte une fonction qui définit la source de la timeline : soit scroll() pour une timeline de progression de défilement, soit view() pour une timeline de progression de la vue.
Timeline de progression de défilement : `scroll()`
La fonction scroll() lie une animation à la position de défilement d'un conteneur. Sa forme la plus courante est scroll(scroller, axis).
scroller: SpĂ©cifie quel Ă©lĂ©ment de dĂ©filement suivre. Il peut s'agir deroot(la fenĂȘtre d'affichage du document),self(l'Ă©lĂ©ment lui-mĂȘme, s'il est un scroller), ounearest(l'ancĂȘtre scroller le plus proche).axis: SpĂ©cifie l'axe de dĂ©filement Ă suivre. Il peut s'agir deblock(la direction principale du flux de contenu, gĂ©nĂ©ralement verticale),inline(perpendiculaire Ă block, gĂ©nĂ©ralement horizontale),y, oux.
Exemple : une simple barre de progression au défilement du document
Créons une barre de progression en haut de la page qui grandit à mesure que l'utilisateur fait défiler vers le bas.
<!-- HTML -->
<div id="progress-bar"></div>
<!-- CSS -->
@keyframes grow-progress {
from { transform: scaleX(0); }
to { transform: scaleX(1); }
}
#progress-bar {
position: fixed;
top: 0;
left: 0;
height: 10px;
width: 100%;
background-color: dodgerblue;
transform-origin: left;
/* Détacher du temps, lier au défilement du document */
animation: grow-progress linear;
animation-timeline: scroll(root block);
}
Dans cet exemple, l'animation grow-progress est désormais pilotée par le défilement du document principal (root) sur son axe vertical (block). Lorsque vous faites défiler de 0 % à 100 % de la page, la transformation scaleX de la barre de progression passe de 0 à 1.
Timeline de progression de la vue : `view()`
La fonction view() lie une animation à la visibilité d'un élément au sein de son scroller. C'est incroyablement utile pour déclencher des animations de "révélation" à mesure que les éléments apparaissent.
Sa syntaxe est view(axis, inset).
axis: Optionnel, mĂȘmes valeurs que dansscroll()(par ex.,block). DĂ©finit quel axe du scrollport prendre en considĂ©ration.inset: Optionnel, vous permet d'ajuster les limites de la fenĂȘtre d'affichage utilisĂ©e pour calculer la visibilitĂ©, similaire Ă la propriĂ©tĂ©rootMarginde l'IntersectionObserver.
Exemple : Apparition progressive d'un élément
<!-- HTML -->
<div class="content-box reveal">
Cette boßte apparaßtra en fondu en entrant dans l'écran.
</div>
<!-- CSS -->
@keyframes fade-in {
from { opacity: 0; }
to { opacity: 1; }
}
.reveal {
/* Lier l'animation à la visibilité de cet élément */
animation: fade-in linear;
animation-timeline: view();
}
Ici, l'animation fade-in est liĂ©e Ă l'Ă©lĂ©ment .reveal lui-mĂȘme. L'animation progressera Ă mesure que l'Ă©lĂ©ment traverse la fenĂȘtre d'affichage. Mais comment cela se mappe-t-il exactement ? Quand commence-t-elle et quand se termine-t-elle ? C'est lĂ que animation-range entre en jeu.
La star du spectacle : `animation-range`
Alors que animation-timeline définit le contexte, animation-range fournit le contrÎle crucial. Elle définit quelle partie de la timeline est considérée comme "active" et la mappe à la progression de 0 % à 100 % de votre animation @keyframes.
La syntaxe de base est :
animation-range: <range-start> <range-end>;
Cela indique au navigateur : "Quand la timeline atteint le point <range-start>, l'animation doit ĂȘtre Ă 0 %. Quand elle atteint le point <range-end>, l'animation doit ĂȘtre Ă 100 %."
Les valeurs pour <range-start> et <range-end> peuvent ĂȘtre de plusieurs types :
- Mots-clés (pour
view()) : Des noms spéciaux et trÚs intuitifs commeentry,exit,cover, etcontain. Nous les explorerons en détail. - Pourcentages : Un pourcentage de la durée totale de la timeline. Pour une timeline
scroll(),0%est le haut et100%est le bas. - Longueurs CSS : Une valeur de longueur fixe comme
100pxou20rem. Cela spécifie un point à ce décalage de défilement depuis le début de la timeline.
Vous pouvez mĂȘme combiner des mots-clĂ©s avec des pourcentages ou des longueurs pour un contrĂŽle extrĂȘmement prĂ©cis, comme entry 50% ou cover 200px.
Analyse pratique approfondie : `animation-range` avec les timelines `scroll()`
Lorsque vous travaillez avec une timeline scroll(), vous mappez votre animation à la plage de défilement globale du scroller. Voyons comment animation-range nous aide à cibler des parties spécifiques de ce parcours.
Cibler une section de défilement spécifique
Imaginez que vous ayez un long article et que vous souhaitiez qu'un graphique spécifique ne s'anime que lorsque l'utilisateur fait défiler la moitié centrale de la page.
@keyframes spin-and-grow {
from { transform: rotate(0deg) scale(0.5); opacity: 0; }
to { transform: rotate(360deg) scale(1); opacity: 1; }
}
.special-graphic {
animation: spin-and-grow linear;
animation-timeline: scroll(root block);
/* L'animation commence à 25% du défilement et se termine à 75% */
animation-range: 25% 75%;
}
Comment ça marche :
- Avant que l'utilisateur n'ait fait défiler 25 % de la page, l'animation est maintenue à son état 0 % (
rotate(0deg) scale(0.5) opacity: 0). - Lorsque l'utilisateur fait défiler de la marque de 25 % à celle de 75 %, l'animation progresse de 0 % à 100 %.
- Une fois que l'utilisateur a dépassé la marque de 75 %, l'animation est maintenue à son état 100 % (
rotate(360deg) scale(1) opacity: 1).
Ce simple ajout de animation-range nous donne un contrÎle puissant sur le timing et le placement de nos effets au sein de l'expérience de défilement plus large.
Utiliser des longueurs absolues
Vous pouvez également utiliser des longueurs absolues. Par exemple, si vous voulez qu'une animation ne se produise que sur les 500 premiers pixels de défilement :
.hero-animation {
animation: fade-out linear;
animation-timeline: scroll(root block);
/* L'animation commence au décalage de défilement 0px et se termine à 500px */
animation-range: 0px 500px;
}
C'est parfait pour les animations d'introduction dans la section principale (hero) d'une page, qui doivent se terminer une fois que l'utilisateur a commencé à faire défiler plus profondément dans le contenu.
MaĂźtriser `animation-range` avec les timelines `view()`
C'est lĂ que animation-range devient vraiment magique. Lorsqu'elle est utilisĂ©e avec une timeline view(), les valeurs de la plage ne sont pas basĂ©es sur la hauteur de dĂ©filement totale du document, mais sur la visibilitĂ© de l'Ă©lĂ©ment dans la fenĂȘtre d'affichage. C'est ici que les plages nommĂ©es spĂ©ciales entrent en jeu.
Explication des plages nommées
Imaginez un Ă©lĂ©ment (le "sujet") et la fenĂȘtre d'affichage (le "scroller"). Les plages nommĂ©es dĂ©crivent la relation entre ces deux boĂźtes.
entry: La phase oĂč le sujet entre dans la fenĂȘtre d'affichage. Elle commence au moment oĂč le bord infĂ©rieur du sujet franchit le bord supĂ©rieur de la fenĂȘtre d'affichage et se termine lorsque le bord infĂ©rieur du sujet franchit le bord infĂ©rieur de la fenĂȘtre d'affichage.exit: La phase oĂč le sujet quitte la fenĂȘtre d'affichage. Elle commence lorsque le bord supĂ©rieur du sujet franchit le bord supĂ©rieur de la fenĂȘtre d'affichage et se termine lorsque le bord supĂ©rieur du sujet franchit le bord infĂ©rieur de la fenĂȘtre d'affichage.cover: La phase oĂč le sujet est assez grand pour couvrir complĂštement la fenĂȘtre d'affichage. Elle commence lorsque le bord supĂ©rieur du sujet atteint le bord supĂ©rieur de la fenĂȘtre d'affichage et se termine lorsque le bord infĂ©rieur du sujet atteint le bord infĂ©rieur de la fenĂȘtre d'affichage. Si le sujet est plus petit que la fenĂȘtre d'affichage, cette phase ne se produit jamais.contain: La phase oĂč le sujet est entiĂšrement contenu dans la fenĂȘtre d'affichage. Elle commence lorsque le bord infĂ©rieur du sujet entre par le bord infĂ©rieur de la fenĂȘtre d'affichage et se termine lorsque le bord supĂ©rieur du sujet sort par le bord supĂ©rieur de la fenĂȘtre d'affichage. Si le sujet est plus grand que la fenĂȘtre d'affichage, cette phase ne se produit jamais.
Exemple pratique : l'effet classique de "révélation au défilement"
Recréons l'une des animations basées sur le défilement les plus courantes : un élément qui apparaßt en fondu et glisse en place à mesure qu'il entre à l'écran. Traditionnellement, cela nécessitait un Intersection Observer en JavaScript. Maintenant, ce ne sont que quelques lignes de CSS.
<!-- HTML -->
<section>
<div class="content-box reveal">BoĂźte 1</div>
<div class="content-box reveal">BoĂźte 2</div>
<div class="content-box reveal">BoĂźte 3</div>
</section>
<!-- CSS -->
@keyframes fade-and-slide-in {
from { opacity: 0; transform: translateY(50px); }
to { opacity: 1; transform: translateY(0); }
}
.reveal {
animation: fade-and-slide-in linear both; /* 'both' est important ! */
animation-timeline: view();
/* Démarrer l'animation quand l'élément entre, terminer quand il est à mi-chemin de son entrée */
animation-range: entry 0% entry 50%;
}
Décortiquons cette valeur animation-range :
animation-fill-mode: both;est crucial. Il garantit qu'avant la plage active de l'animation, l'Ă©lĂ©ment reste dans son Ă©tatfrom(invisible et dĂ©calĂ© vers le bas), et aprĂšs la plage, il reste dans son Ă©tatto(entiĂšrement visible et en place).entry 0%: Le point de dĂ©part. Cela fait rĂ©fĂ©rence au tout dĂ©but de la phaseentryâ le moment exact oĂč le bas de notre Ă©lĂ©ment touche le bas de la fenĂȘtre d'affichage.entry 50%: Le point de fin. Cela fait rĂ©fĂ©rence au moment oĂč l'Ă©lĂ©ment a accompli 50 % de son parcours Ă travers la phaseentry. Ă ce stade, l'animation sera terminĂ©e Ă 100 %.
Cela donne un effet agrĂ©able oĂč l'Ă©lĂ©ment est entiĂšrement visible et Ă sa position finale bien avant que l'utilisateur ne l'ait fait dĂ©filer jusqu'au centre de l'Ă©cran. Vous pouvez ajuster ces pourcentages pour obtenir la sensation exacte que vous souhaitez. Par exemple, entry 25% entry 75% crĂ©erait une animation plus longue.
ContrÎle avancé : créer un effet de parallaxe
Essayons un effet plus complexe. Nous allons faire en sorte qu'une image de fond se dĂ©place Ă une vitesse diffĂ©rente de celle du dĂ©filement, mais seulement pendant que son conteneur couvre la fenĂȘtre d'affichage.
<!-- HTML -->
<div class="parallax-container">
<div class="parallax-bg"></div>
<h2>Section Parallaxe</h2>
</div>
<!-- CSS -->
@keyframes parallax-shift {
from { background-position: 50% -50px; }
to { background-position: 50% 50px; }
}
.parallax-container {
position: relative;
height: 100vh;
overflow: hidden;
}
.parallax-bg {
position: absolute;
inset: -50px; /* Le rendre plus haut que le conteneur pour permettre le mouvement */
background-image: url('votre-image.jpg');
background-size: cover;
animation: parallax-shift linear both;
animation-timeline: view(block);
/* Animer sur toute la phase 'cover' */
animation-range: cover 0% cover 100%;
}
Dans ce cas, l'animation parallax-shift est liĂ©e Ă la timeline de l'Ă©lĂ©ment parallax-bg. L'animation-range est dĂ©finie sur la durĂ©e complĂšte de la phase cover. Cela signifie que l'animation ne commence Ă progresser que lorsque le conteneur est assez grand pour couvrir la fenĂȘtre d'affichage et est positionnĂ© de telle sorte que son sommet est au sommet de la fenĂȘtre d'affichage. Elle se termine lorsque le bas du conteneur atteint le bas de la fenĂȘtre d'affichage. Le rĂ©sultat est un effet de parallaxe fluide et performant qui est parfaitement synchronisĂ© avec la position de dĂ©filement.
Combiner le tout : raccourcis et meilleures pratiques
Le raccourci `animation`
Pour rendre la syntaxe encore plus concise, les propriĂ©tĂ©s de timeline et de range peuvent ĂȘtre incluses directement dans la propriĂ©tĂ© raccourcie animation. C'est une nouvelle syntaxe proposĂ©e qui gagne en soutien.
Notre exemple de rĂ©vĂ©lation au dĂ©filement pourrait ĂȘtre réécrit comme suit :
.reveal {
animation: fade-and-slide-in linear both view() entry 0% entry 50%;
}
Cette seule ligne remplace les trois propriĂ©tĂ©s distinctes animation, animation-timeline et animation-range. C'est propre, efficace et garde toute la logique de l'animation au mĂȘme endroit.
Considérations sur la performance
Le principal avantage des animations pilotĂ©es par le dĂ©filement est la performance. Pour conserver cet avantage, vous devez privilĂ©gier l'animation de propriĂ©tĂ©s qui peuvent ĂȘtre gĂ©rĂ©es par le thread du compositeur. Celles-ci sont principalement :
transform(translate, scale, rotate)opacity
L'animation de propriétés comme width, height, margin, ou color fonctionnera toujours, mais elles peuvent déclencher des opérations de mise en page et de rendu, qui se produisent sur le thread principal. Bien que souvent plus fluides que les alternatives basées sur JS, elles ne seront pas aussi performantes que les animations uniquement basées sur le compositeur.
Accessibilité et solutions de repli
Il est crucial de construire pour tous les utilisateurs. Les animations pilotées par le défilement sont excellentes, mais certains utilisateurs trouvent le mouvement distrayant ou nauséeux.
1. Respecter les préférences de l'utilisateur : Encadrez toujours votre CSS lié au mouvement dans une media query prefers-reduced-motion.
@media (prefers-reduced-motion: no-preference) {
.reveal {
animation: fade-and-slide-in linear both;
animation-timeline: view();
animation-range: entry 0% entry 50%;
}
}
2. Fournir des solutions de repli pour les anciens navigateurs : Comme il s'agit d'une nouvelle technologie, vous devez tenir compte des navigateurs qui ne la prennent pas encore en charge. La rÚgle @supports est votre meilleure amie ici. Fournissez un état par défaut simple et non animé, puis améliorez-le pour les navigateurs compatibles.
/* Ătat par dĂ©faut pour tous les navigateurs */
.reveal {
opacity: 1;
transform: translateY(0);
}
/* Amélioration pour les navigateurs compatibles */
@supports (animation-timeline: view()) {
@media (prefers-reduced-motion: no-preference) {
.reveal {
opacity: 0; /* Définir l'état initial pour l'animation */
transform: translateY(50px);
animation: fade-and-slide-in linear both;
animation-timeline: view();
animation-range: entry 0% entry 50%;
}
}
}
Support des navigateurs et perspectives
Fin 2023, les animations CSS pilotées par le défilement sont prises en charge dans Chrome et Edge. Elles sont en cours de développement actif dans Firefox et sont à l'étude par Safari. Comme pour toute fonctionnalité de pointe de la plateforme web, il est essentiel de consulter des ressources comme CanIUse.com pour obtenir les derniÚres informations sur le support.
L'introduction de cette technologie marque un changement significatif dans le développement web. Elle permet aux designers et aux développeurs de créer des expériences riches, interactives et performantes de maniÚre déclarative, réduisant notre dépendance à JavaScript pour toute une classe de modÚles d'interface utilisateur courants. à mesure que le support des navigateurs mûrit, attendez-vous à voir les animations pilotées par le défilement devenir un outil essentiel dans la boßte à outils de chaque développeur front-end.
Conclusion
Les animations CSS pilotées par le défilement, et plus particuliÚrement la propriété animation-range, représentent un bond en avant monumental pour l'animation web. Nous sommes passés de timelines basées sur le temps à des timelines basées sur la progression, débloquant la capacité de créer des interactions complexes, sensibles au défilement, avec une performance et une simplicité inégalées.
Nous avons appris que :
animation-timelinelie une animation à une timeline de progressionscroll()ouview().animation-rangenous donne un contrÎle précis, en mappant une portion spécifique de cette timeline à nos keyframes d'animation.- Avec les timelines
view(), des plages nommées puissantes commeentry,exit,cover, etcontainfournissent un moyen intuitif de contrÎler les animations en fonction de la visibilité d'un élément. - En s'en tenant aux propriétés favorables au compositeur et en fournissant des solutions de repli, nous pouvons utiliser cette technologie dÚs aujourd'hui pour créer des expériences utilisateur accessibles, performantes et agréables.
Les jours de lutte avec des écouteurs de défilement saccadés et bloquant le thread principal pour des effets simples sont comptés. L'avenir de l'animation basée sur le défilement est là , il est déclaratif, et il s'écrit en CSS. Il est temps de commencer à expérimenter.