Cours Vue.js · Module 13: Transitions et animations
Modèles d'animation avancés
Dans cette leçon5
Dans les systèmes avancés du NOVA LAB, nous avons besoin d'effets sophistiqués - chargement en cascade des éléments du tableau de bord, animation au premier affichage de la page, contrôle précis de la durée, et respect des préférences de mouvement des utilisateurs. Apprends les modèles qui donnent aux interfaces une allure professionnelle.
Appear - animation au montage
Par défaut, <Transition> n'anime l'élément que lors du basculement de v-if/v-show. L'attribut appear fait que l'animation se déclenche aussi lors du premier rendu (montage) du composant :
1<Transition appear name="fade">
2 <div>Cet élément s'anime au chargement de la page</div>
3</Transition>C'est la solution idéale pour les éléments visibles juste après le chargement - le logo de la station, l'en-tête du tableau de bord, le panneau d'état. Sans appear, ces éléments seraient simplement « là » sans aucune animation d'entrée.
Tu peux utiliser des classes CSS spéciales pour l'animation appear (indépendantes des classes enter normales) :
1<Transition
2 appear
3 appear-from-class="appear-start"
4 appear-active-class="appear-running"
5 appear-to-class="appear-end"
6>
7 <div>Animation appear personnalisée</div>
8</Transition>Ou avec des bibliothèques :
1<Transition
2 appear
3 appear-active-class="animate__animated animate__fadeInDown"
4>
5 <header>Centre de contrôle NOVA LAB</header>
6</Transition>Animation de liste échelonnée (staggered)
L'un des modèles les plus impressionnants - l'apparition en cascade des éléments d'une liste, où chaque élément suivant apparaît avec un délai croissant. Cela ressemble à des données qui s'affichent sur un tableau de bord holographique du NOVA LAB, élément par élément :
1<TransitionGroup
2 appear
3 :css="false"
4 @before-enter="onBeforeEnter"
5 @enter="onEnter"
6 tag="div"
7>
8 <div v-for="(item, index) in items" :key="item.id" :data-index="index">
9 {{ item.name }}
10 </div>
11</TransitionGroup>La clé, c'est l'attribut :data-index - il transmet l'index de l'élément au hook JS, qui calcule le délai :
1function onBeforeEnter(el) {
2 el.style.opacity = 0
3 el.style.transform = 'translateY(20px)'
4}
5
6function onEnter(el, done) {
7 // Chaque élément suivant a un délai de 150 ms de plus
8 const delay = el.dataset.index * 150
9
10 setTimeout(() => {
11 el.style.transition = 'all 0.5s ease'
12 el.style.opacity = 1
13 el.style.transform = 'translateY(0)'
14 el.addEventListener('transitionend', done, { once: true })
15 }, delay)
16}L'effet : l'élément 0 apparaît immédiatement, l'élément 1 après 150 ms, l'élément 2 après 300 ms, etc. Pour 10 éléments, l'animation entière prend 1,5 s + 0,5 s (durée de l'animation elle-même) = ~2 s.
Astuce : Limite le délai à un maximum de ~1 s pour que l'utilisateur n'attende pas trop longtemps les derniers éléments :
1const delay = Math.min(el.dataset.index * 100, 1000)Durée explicite
Quand un élément a à la fois une transition et une animation CSS, ou quand des éléments imbriqués ont des durées d'animation différentes, Vue peut ne pas détecter correctement le point final. L'attribut :duration te permet de spécifier explicitement la durée en millisecondes :
1<!-- Même durée pour enter et leave -->
2<Transition :duration="500">...</Transition>
3
4<!-- Durées différentes pour enter et leave -->
5<Transition :duration="{ enter: 300, leave: 500 }">...</Transition>C'est particulièrement utile quand :
- Tu animes des éléments imbriqués avec des durées différentes
- Tu combines transition et animation CSS sur le même élément
- Tu utilises des bibliothèques externes dont la durée n'est pas détectée automatiquement
Accessibilité - prefers-reduced-motion
Respecte les réglages de mouvement des utilisateurs. Les personnes atteintes de troubles vestibulaires ou d'épilepsie peuvent avoir activé la préférence prefers-reduced-motion. Ton CSS doit en tenir compte :
1/* Animations normales */
2.fade-enter-active,
3.fade-leave-active {
4 transition: opacity 0.3s ease, transform 0.3s ease;
5}
6
7.fade-enter-from,
8.fade-leave-to {
9 opacity: 0;
10 transform: translateY(10px);
11}
12
13/* Désactive les animations pour les utilisateurs qui n'en veulent pas */
14@media (prefers-reduced-motion: reduce) {
15 .fade-enter-active,
16 .fade-leave-active {
17 transition: none;
18 }
19
20 .fade-enter-from,
21 .fade-leave-to {
22 opacity: 1;
23 transform: none;
24 }
25}Tu peux aussi gérer cela en JavaScript :
1const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches
2
3function onEnter(el, done) {
4 if (prefersReducedMotion) {
5 done() // Saute l'animation
6 return
7 }
8 // Animation normale...
9}Bonnes pratiques de performance
N'anime que
transformetopacity- ces propriétés sont accélérées par le GPU et ne provoquent pas de reflow/repaint. Évite d'animerwidth,height,top,left,margin,padding.Utilise
will-changepour les animations lourdes - cela informe le navigateur d'une animation à venir, ce qui permet une optimisation :
1.heavy-animation-enter-active {
2 will-change: transform, opacity;
3 transition: all 0.5s ease;
4}Privilégie le CSS au JS - les animations CSS sont optimisées par le navigateur et s'exécutent sur un thread séparé. N'utilise les hooks JS que lorsque tu as besoin de valeurs dynamiques.
Durées courtes - les animations d'interface doivent durer 200-500 ms. Les animations plus longues ralentissent l'interaction et frustrent les utilisateurs.
Teste sur les appareils mobiles - des animations qui tournent parfaitement sur ordinateur peuvent ramer sur des téléphones plus anciens.
Code de cette leçon : App.vue
1<script setup>
2import { ref } from 'vue'
3
4// Appear - animation au montage
5const items = ref([
6 { id: 1, name: 'Survie', delay: 0 },
7 { id: 2, name: 'Navigation', delay: 100 },
8 { id: 3, name: 'Communications', delay: 200 },
9 { id: 4, name: 'Réseau électrique', delay: 300 },
10 { id: 5, name: 'Laboratoire scientifique', delay: 400 }
11])
12
13function onBeforeEnter(el) {
14 el.style.opacity = 0
15 el.style.transform = 'translateY(20px)'
16}
17
18function onEnter(el, done) {
19 const delay = el.dataset.index * 150
20 setTimeout(() => {
21 el.style.transition = 'all 0.5s ease'
22 el.style.opacity = 1
23 el.style.transform = 'translateY(0)'
24 el.addEventListener('transitionend', done, { once: true })
25 }, delay)
26}
27</script>
28
29<template>
30 <div class="nova-lab">
31 <h1>Liste échelonnée + Appear</h1>
32
33 <TransitionGroup
34 appear
35 :css="false"
36 @before-enter="onBeforeEnter"
37 @enter="onEnter"
38 tag="div"
39 class="systems"
40 >
41 <div
42 v-for="(item, index) in items"
43 :key="item.id"
44 :data-index="index"
45 class="system-card"
46 >
47 <span class="dot">●</span>
48 {{ item.name }}
49 </div>
50 </TransitionGroup>
51 </div>
52</template>
53
54<style scoped>
55.nova-lab {
56 background: #0a0e27;
57 color: #00ff88;
58 min-height: 100vh;
59 padding: 20px;
60 font-family: monospace;
61}
62h1 { color: #00ff88; }
63.systems { margin-top: 20px; }
64.system-card {
65 display: flex;
66 align-items: center;
67 gap: 12px;
68 background: rgba(0, 180, 216, 0.1);
69 border: 1px solid #00b4d8;
70 padding: 14px 20px;
71 margin: 8px 0;
72 border-radius: 8px;
73 font-size: 14px;
74}
75.dot { color: #00ff88; }
76</style>Tu as repéré une erreur dans cette leçon ?
Teste tes connaissances
Réponds aux questions de cette leçon. Choisis une réponse pour voir tout de suite si elle est correcte.
1. Que fait l'attribut appear dans <Transition> ?
2. Comment définit-on une durée d'animation explicite dans <Transition> ?
Voici 2 des 4 questions de cette leçon. Réponds aux autres dans le jeu.
Tâches pratiques dans le jeu
- Tri vertical
Range les étapes pour implémenter une animation de liste échelonnée (avec délai) :
- Éditeur de code
Utilise data-index et gsap/setTimeout pour une animation échelonnée dans TransitionGroup.
- Tri horizontal
Range l'attribut appear avec une classe personnalisée :
- Clique dans l'ordre
Range le code pour passer un index à un élément de liste :
- Tri vertical
Range les techniques d'animation de la plus simple à la plus avancée :
- Tri horizontal
Range la syntaxe de duration avec des temps enter/leave différents :
- Clique dans l'ordre
Range les hooks JavaScript dans l'ordre où ils sont appelés (animation de sortie) :
- Clique dans l'ordre
Range la déclaration raccourcie transition CSS :
- Tri vertical
Range les 6 classes CSS ajoutées par <Transition> dans l'ordre chronologique :