Cours HTML et CSS · Module 6: Animations CSS
Performance des animations CSS - optimisation et accélération GPU
Dans cette leçon13
Bienvenue dans l'atelier des bâtisseurs de pyramides ! Tout comme les anciens Égyptiens devaient construire les pyramides efficacement pour économiser ressources et temps, nous devons créer des animations performantes qui restent fluides même sur des appareils plus faibles. Apprends les secrets de l'accélération GPU, de will-change, et comment éviter les animations lentes !
Pourquoi la performance des animations est-elle importante ?
Problème : les animations peuvent provoquer :
- Une chute des FPS (images par seconde) en dessous de 60 FPS
- Des ralentissements et des « saccades »
- Une décharge de la batterie sur les appareils mobiles
- Une mauvaise expérience utilisateur (UX)
Objectif : 60 FPS fluides = 16,67 ms par image
Analogie égyptienne : tout comme les bâtisseurs de pyramides devaient utiliser les bonnes techniques (leviers, rampes) pour soulever de lourds blocs, nous devons utiliser les bonnes propriétés CSS pour que les animations soient légères et rapides.
GPU vs CPU - comprendre le rendu
CPU (Central Processing Unit)
- Le processeur principal de l'ordinateur
- Polyvalent
- Plus lent pour les graphismes
GPU (Graphics Processing Unit)
- Le processeur graphique
- Optimisé pour les calculs graphiques
- Beaucoup plus rapide pour les animations et les transformations
Différence clé :
- CPU : traitement séquentiel
- GPU : traitement parallèle de milliers de pixels simultanément
Propriétés accélérées par le GPU (RAPIDES) vs liées au CPU (LENTES)
Accéléré par le GPU (à TOUJOURS utiliser pour les animations)
1/* Transform - toutes les fonctions */
2.fast {
3 transform: translate(100px, 50px); /* GPU */
4 transform: scale(1.5); /* GPU */
5 transform: rotate(45deg); /* GPU */
6 transform: skew(10deg); /* GPU */
7 transform: translateZ(0); /* GPU */
8 transform: translate3d(10px, 20px, 0);/* GPU */
9}
10
11/* Opacity */
12.fast {
13 opacity: 0.5; /* GPU */
14}Pourquoi elles sont rapides :
- Elles ne provoquent pas de reflow (recalcul de la mise en page)
- Elles ne provoquent pas de repaint (redessin)
- Le GPU les rend dans une couche séparée (compositing layer)
Lié au CPU (à ÉVITER dans les animations)
1/* Propriétés qui modifient la mise en page */
2.slow {
3 width: 300px; /* CPU - reflow de toute la page */
4 height: 200px; /* CPU - reflow de toute la page */
5 margin: 20px; /* CPU - reflow de toute la page */
6 padding: 10px; /* CPU - reflow de toute la page */
7 top: 100px; /* CPU - reflow de l'élément */
8 left: 50px; /* CPU - reflow de l'élément */
9 font-size: 20px; /* CPU - reflow du texte */
10}
11
12/* Propriétés qui modifient l'apparence */
13.slow {
14 background: red; /* CPU - repaint */
15 color: blue; /* CPU - repaint */
16 border: 1px solid; /* CPU - repaint */
17 box-shadow: 0 0 10px;/* CPU - repaint (lourd !) */
18}Pourquoi elles sont lentes :
- Reflow = le navigateur doit recalculer la position de TOUS les éléments
- Repaint = le navigateur doit redessiner les pixels
- Elles bloquent le thread principal
Exemples pratiques - LENT vs RAPIDE
Exemple 1 : déplacer un élément
1/* LENT - animer left */
2.box-slow {
3 position: relative;
4 left: 0;
5 transition: left 0.3s;
6}
7
8.box-slow:hover {
9 left: 100px; /* Provoque un reflow à chaque image ! */
10}
11
12/* RAPIDE - animer transform */
13.box-fast {
14 transform: translateX(0);
15 transition: transform 0.3s;
16}
17
18.box-fast:hover {
19 transform: translateX(100px); /* Accéléré par le GPU ! */
20}Résultat :
- Lent : ~30-40 FPS (ralentissements visibles)
- Rapide : 60 FPS (fluide)
Exemple 2 : agrandir un élément
1/* LENT - animer width/height */
2.card-slow {
3 width: 200px;
4 height: 300px;
5 transition: width 0.3s, height 0.3s;
6}
7
8.card-slow:hover {
9 width: 220px; /* Reflow ! */
10 height: 330px; /* Reflow ! */
11}
12
13/* RAPIDE - animer scale */
14.card-fast {
15 width: 200px;
16 height: 300px;
17 transform: scale(1);
18 transition: transform 0.3s;
19}
20
21.card-fast:hover {
22 transform: scale(1.1); /* GPU ! 220px x 330px */
23}Exemple 3 : apparition/disparition en fondu
1/* LENT - animer visibility */
2.modal-slow {
3 visibility: visible;
4 transition: visibility 0.3s;
5}
6
7.modal-slow.hidden {
8 visibility: hidden; /* Ne peut pas être animé ! Saut ! */
9}
10
11/* RAPIDE - animer opacity */
12.modal-fast {
13 opacity: 1;
14 transition: opacity 0.3s;
15}
16
17.modal-fast.hidden {
18 opacity: 0; /* Animation GPU fluide ! */
19 pointer-events: none; /* Désactiver les interactions */
20}Exemple 4 : box shadow (très coûteux !)
1/* TRÈS LENT - animer box-shadow */
2.button-slow {
3 box-shadow: 0 2px 4px rgba(0,0,0,0.1);
4 transition: box-shadow 0.3s;
5}
6
7.button-slow:hover {
8 box-shadow: 0 8px 16px rgba(0,0,0,0.3); /* Très lourd ! */
9}
10
11/* PLUS RAPIDE - pseudo-élément avec opacity */
12.button-fast {
13 position: relative;
14}
15
16.button-fast::after {
17 content: '';
18 position: absolute;
19 inset: 0;
20 box-shadow: 0 8px 16px rgba(0,0,0,0.3);
21 opacity: 0;
22 transition: opacity 0.3s;
23 pointer-events: none;
24}
25
26.button-fast:hover::after {
27 opacity: 1; /* Animer uniquement opacity ! */
28}will-change - prévenir le navigateur des changements à venir
will-change est un indice pour le navigateur : « Hé, je vais animer cette propriété, prépare-toi ! »
Comment fonctionne will-change
1.element {
2 will-change: transform;
3 /* Le navigateur crée une couche GPU AVANT l'animation */
4}
5
6.element:hover {
7 transform: scale(1.2); /* Déjà prêt ! */
8}Ce qui se passe :
- Le navigateur crée une couche séparée (compositing layer) pour l'élément
- L'élément est rendu par le GPU
- L'animation est instantanée et fluide
Quand utiliser will-change
1/* BON - pour les éléments fréquemment animés */
2.menu-item {
3 will-change: transform;
4 transition: transform 0.2s;
5}
6
7.menu-item:hover {
8 transform: translateY(-5px);
9}
10
11/* BON - pour les animations keyframes */
12.spinner {
13 will-change: transform;
14 animation: spin 1s linear infinite;
15}
16
17@keyframes spin {
18 to { transform: rotate(360deg); }
19}
20
21/* BON - ajouter dynamiquement avant l'animation */
22.modal {
23 /* Pas de will-change par défaut */
24}
25
26.modal.opening {
27 will-change: transform, opacity; /* Ajouter avant l'animation */
28}
29
30.modal.open {
31 will-change: auto; /* Retirer après l'animation ! */
32}Quand NE PAS utiliser will-change
1/* MAUVAIS - sur tous les éléments */
2* {
3 will-change: transform; /* Utilise BEAUCOUP de mémoire ! */
4}
5
6/* MAUVAIS - sur des éléments statiques */
7.logo {
8 will-change: transform; /* Le logo ne bouge pas ! */
9}
10
11/* MAUVAIS - trop de propriétés */
12.element {
13 will-change: transform, opacity, width, height, background, color;
14 /* Trop - contre-productif ! */
15}
16
17/* MAUVAIS - laissé en permanence */
18.button {
19 will-change: transform; /* Laissé pour toujours = fuite de mémoire */
20}Règles pour will-change :
- Uniquement pour les éléments animés
- Seulement 1-2 propriétés à la fois
- Ajouter avant l'animation, retirer après l'animation
- Teste l'utilisation de la mémoire - cela peut être contre-productif !
Ajouter will-change dynamiquement (JavaScript)
1const element = document.querySelector('.box');
2
3// Ajouter avant l'animation (par ex. au mouseenter)
4element.addEventListener('mouseenter', () => {
5 element.style.willChange = 'transform';
6});
7
8// Retirer après l'animation (au transitionend)
9element.addEventListener('transitionend', () => {
10 element.style.willChange = 'auto';
11});Forcer l'accélération GPU - l'astuce translateZ(0)
Si le navigateur ne crée pas automatiquement de couche GPU, tu peux la forcer :
1.element {
2 /* Forcer une couche GPU */
3 transform: translateZ(0);
4 /* ou */
5 transform: translate3d(0, 0, 0);
6 /* ou */
7 will-change: transform;
8}Exemple pratique :
1/* Image qui sera agrandie */
2.image {
3 transform: translateZ(0); /* Forcer le GPU */
4 transition: transform 0.3s;
5}
6
7.image:hover {
8 transform: scale(1.1); /* Maintenant GPU garanti */
9}Attention : ne l'utilise pas sur tous les éléments - cela consomme de la mémoire GPU !
Éviter l'animation de width/height - le layout thrashing
Problème : animer width ou height provoque un reflow à chaque image.
Méthode lente - animation de width
1.progress-bar-slow {
2 width: 0%;
3 transition: width 2s;
4}
5
6.progress-bar-slow.complete {
7 width: 100%; /* Reflow à chaque image ! */
8}Méthode rapide - transform: scaleX
1.progress-bar-fast {
2 width: 100%; /* Pleine largeur immédiatement */
3 transform: scaleX(0); /* Échelle 0% */
4 transform-origin: left; /* Grandir depuis la gauche */
5 transition: transform 2s;
6}
7
8.progress-bar-fast.complete {
9 transform: scaleX(1); /* Échelle 100% - GPU ! */
10}Alternative - clip-path
1.progress-bar-clip {
2 width: 100%;
3 background: linear-gradient(to right, #3498db, #2ecc71);
4 clip-path: inset(0 100% 0 0); /* Cacher le côté droit */
5 transition: clip-path 2s;
6}
7
8.progress-bar-clip.complete {
9 clip-path: inset(0 0 0 0); /* Tout afficher */
10}requestAnimationFrame vs animations CSS
Animations CSS - PRÉFÉRÉES
Avantages :
- Optimisées par le navigateur
- S'exécutent dans un thread séparé (compositor thread)
- Fluides même quand le thread principal est occupé
- Moins de code
- Accélération GPU automatique
1/* Animation CSS - préférée */
2.box {
3 animation: slide 1s ease-in-out infinite;
4}
5
6@keyframes slide {
7 0% { transform: translateX(0); }
8 100% { transform: translateX(100px); }
9}requestAnimationFrame (rAF) - pour les animations complexes
Quand l'utiliser :
- Animations dépendant de l'interaction de l'utilisateur (scroll, souris)
- Animations avec des valeurs dynamiques (physique, easing)
- Synchronisation de plusieurs animations
- Animations Canvas/WebGL
1/* JavaScript rAF - pour les cas complexes */
2let position = 0;
3const box = document.querySelector('.box');
4
5function animate() {
6 position += 2;
7
8 // Utilise transform, pas left !
9 box.style.transform = `translateX(${position}px)`;
10
11 if (position < 500) {
12 requestAnimationFrame(animate);
13 }
14}
15
16requestAnimationFrame(animate);N'utilise PAS setInterval/setTimeout :
1/* MAUVAIS - setInterval */
2setInterval(() => {
3 position += 2;
4 box.style.left = position + 'px'; /* Pas synchronisé avec l'écran ! */
5}, 16);
6
7/* BON - requestAnimationFrame */
8function animate() {
9 position += 2;
10 box.style.transform = `translateX(${position}px)`;
11 requestAnimationFrame(animate);
12}
13requestAnimationFrame(animate);Surveillance des performances - comment mesurer les performances
1. Onglet Performance des Chrome DevTools
Étape par étape :
- Ouvre les DevTools (F12)
- Onglet Performance
- Clique sur Record (cercle rouge)
- Effectue l'animation
- Clique sur Stop
- Analyse :
- FPS - est-ce 60 FPS ?
- CPU - le thread principal est-il occupé ?
- Rendering - combien de temps passé en reflow/repaint ?
2. Onglet Rendering - FPS Meter
1DevTools -> ... (More tools) -> Rendering -> Frame Rendering StatsAffiche :
- Les FPS en temps réel
- L'utilisation de la mémoire GPU
- Le paint flashing (rectangles rouges = repaint)
3. Panneau Layers
1DevTools -> ... (More tools) -> LayersAffiche :
- Quels éléments ont leur propre couche GPU
- Pourquoi la couche a été créée
- Combien de mémoire elle utilise
4. CSS Stats - surveillance de will-change
1/* Vérifier combien d'éléments ont will-change */
2*[style*="will-change"] {
3 outline: 2px solid red !important;
4}Exemples d'optimisation - avant et après
Optimisation 1 : effet de survol de carte
1/* AVANT - lent (4 repaints, 2 reflows) */
2.card-before {
3 transition: all 0.3s;
4}
5
6.card-before:hover {
7 width: 320px; /* Reflow */
8 box-shadow: 0 10px 30px rgba(0,0,0,0.3); /* Repaint */
9 border: 2px solid gold; /* Repaint */
10}
11
12/* APRÈS - rapide (0 reflows, 1 composite) */
13.card-after {
14 position: relative;
15 transition: transform 0.3s;
16}
17
18.card-after::before {
19 content: '';
20 position: absolute;
21 inset: -2px;
22 border: 2px solid gold;
23 opacity: 0;
24 transition: opacity 0.3s;
25}
26
27.card-after::after {
28 content: '';
29 position: absolute;
30 inset: 0;
31 box-shadow: 0 10px 30px rgba(0,0,0,0.3);
32 opacity: 0;
33 transition: opacity 0.3s;
34}
35
36.card-after:hover {
37 transform: scale(1.05); /* GPU */
38}
39
40.card-after:hover::before,
41.card-after:hover::after {
42 opacity: 1; /* GPU */
43}Optimisation 2 : spinner de chargement
1/* AVANT - lent (animation de bordure) */
2.spinner-before {
3 border: 4px solid #f3f3f3;
4 border-top: 4px solid #3498db;
5 border-radius: 50%;
6 animation: spin-slow 1s linear infinite;
7}
8
9@keyframes spin-slow {
10 to {
11 transform: rotate(360deg);
12 border-top-color: #e74c3c; /* Animation de couleur = repaint ! */
13 }
14}
15
16/* APRÈS - rapide (uniquement transform) */
17.spinner-after {
18 border: 4px solid #f3f3f3;
19 border-top: 4px solid #3498db;
20 border-radius: 50%;
21 will-change: transform;
22 animation: spin-fast 1s linear infinite;
23}
24
25@keyframes spin-fast {
26 to {
27 transform: rotate(360deg); /* GPU uniquement ! */
28 }
29}Optimisation 3 : apparition fluide au scroll
1/* AVANT - lent (animation de top + opacity) */
2.reveal-before {
3 position: relative;
4 top: 50px;
5 opacity: 0;
6 transition: top 0.6s, opacity 0.6s;
7}
8
9.reveal-before.visible {
10 top: 0; /* Reflow */
11 opacity: 1; /* GPU */
12}
13
14/* APRÈS - rapide (uniquement transform + opacity) */
15.reveal-after {
16 transform: translateY(50px);
17 opacity: 0;
18 will-change: transform, opacity;
19 transition: transform 0.6s, opacity 0.6s;
20}
21
22.reveal-after.visible {
23 transform: translateY(0); /* GPU */
24 opacity: 1; /* GPU */
25}Liste de vérification de la performance des animations
Propriétés :
- J'anime uniquement
transformetopacity - J'évite
width,height,margin,padding - J'évite
left,top,right,bottom - J'évite
box-shadow(ou je l'anime via un pseudo-élément)
Accélération GPU :
- J'utilise
transformau lieu du positionnement - J'utilise
scaleau lieu dewidth/height - J'ajoute
will-changepour les éléments fréquemment animés - Je retire
will-changeaprès l'animation
Optimisation :
- Je préfère les animations CSS au JavaScript
- Si JS - j'utilise
requestAnimationFrame, passetInterval - Je teste dans l'onglet Performance des Chrome DevTools
- Je vérifie le FPS Meter (objectif : 60 FPS)
- Je vérifie le panneau Layers (utilisation mémoire)
Mobile :
- Je teste sur de vrais appareils mobiles
- Je limite le nombre d'animations simultanées
- Je désactive les animations pour
prefers-reduced-motion
Prefers-reduced-motion - accessibilité
Certains utilisateurs ont activé le réglage « Réduire les animations » dans leur système (vertiges, épilepsie). Respectons cela :
1/* Animations normales */
2.box {
3 transition: transform 0.3s;
4}
5
6.box:hover {
7 transform: scale(1.2) rotate(5deg);
8}
9
10/* Désactiver pour les utilisateurs avec prefers-reduced-motion */
11@media (prefers-reduced-motion: reduce) {
12 .box {
13 transition: none; /* Aucune animation */
14 }
15
16 .box:hover {
17 transform: scale(1.05); /* Seulement un changement subtil */
18 }
19}
20
21/* Ou globalement */
22@media (prefers-reduced-motion: reduce) {
23 *,
24 *::before,
25 *::after {
26 animation-duration: 0.01ms !important;
27 animation-iteration-count: 1 !important;
28 transition-duration: 0.01ms !important;
29 }
30}Récapitulatif
Accéléré par le GPU (RAPIDE) :
transform(translate, scale, rotate, skew)opacityfilter(blur, brightness - mais plus lent que transform)
Lié au CPU (LENT) :
width,height,margin,paddingleft,top,right,bottomfont-size,border-widthbox-shadow(très lent !)background-color,color(repaint)
will-change :
- À utiliser avec parcimonie (1-2 propriétés)
- Ajouter avant l'animation, retirer après
- Ne pas laisser en permanence (fuite de mémoire !)
Modèles performants :
- Utilise
scaleau lieu dewidth/height - Utilise
translateX/Yau lieu deleft/top - Utilise
opacityau lieu devisibility/display - Anime les ombres via des pseudo-éléments avec opacity
Tests :
- Onglet Performance des Chrome DevTools
- FPS Meter (60 FPS = objectif)
- Panneau Layers (mémoire GPU)
- Tester sur des appareils mobiles
Souviens-toi : des animations efficaces, c'est comme un chantier de pyramide bien organisé - utilise les bons outils (GPU = leviers) plutôt que la force brute (CPU = levage à la main), et ta page sera aussi fluide que le sable du désert !
Code de cette leçon : style.css
1* {
2 margin: 0;
3 padding: 0;
4 box-sizing: border-box;
5}
6
7body {
8 font-family: 'Segoe UI', sans-serif;
9 background: linear-gradient(180deg, #ff6b35, #ff9a56, #ffd700);
10 min-height: 100vh;
11 display: flex;
12 justify-content: center;
13 align-items: center;
14 color: white;
15}
16
17.scene {
18 text-align: center;
19 padding: 20px;
20}
21
22h2 {
23 margin-bottom: 30px;
24 color: #3d2914;
25}
26
27.sun-container {
28 position: relative;
29 width: 300px;
30 height: 300px;
31 margin: 0 auto;
32}
33
34.sun {
35 font-size: 80px;
36 position: absolute;
37 top: 50%;
38 left: 50%;
39 transform: translate(-50%, -50%);
40 /* Ajoute l'animation pulseSun */
41 /* animation: pulseSun 2s ease-in-out infinite; */
42}
43
44.ray {
45 position: absolute;
46 width: 4px;
47 height: 60px;
48 background: linear-gradient(180deg, #ffd700, transparent);
49 top: 50%;
50 left: 50%;
51 transform-origin: center bottom;
52 opacity: 0;
53 /* Ajoute l'animation rayGlow */
54 /* animation: rayGlow 3s ease-in-out infinite; */
55}
56
57.ray-1 { transform: translate(-50%, -100%) rotate(0deg); }
58.ray-2 { transform: translate(-50%, -100%) rotate(90deg); }
59.ray-3 { transform: translate(-50%, -100%) rotate(180deg); }
60.ray-4 { transform: translate(-50%, -100%) rotate(270deg); }
61
62/* Ajoute différents animation-delay */
63/* .ray-1 { animation-delay: 0s; } */
64/* .ray-2 { animation-delay: 0.5s; } */
65/* .ray-3 { animation-delay: 1s; } */
66/* .ray-4 { animation-delay: 1.5s; } */
67
68/* Définis @keyframes pulseSun */
69/* @keyframes pulseSun { */
70/* 0%, 100% { transform: translate(-50%, -50%) scale(1); } */
71/* 50% { transform: translate(-50%, -50%) scale(1.2); } */
72/* } */
73
74/* Définis @keyframes rayGlow */
75/* @keyframes rayGlow { */
76/* 0% { opacity: 0; height: 30px; } */
77/* 50% { opacity: 1; height: 80px; } */
78/* 100% { opacity: 0; height: 30px; } */
79/* } */
80
81.hint {
82 margin-top: 30px;
83 color: #3d2914;
84 font-style: italic;
85}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. Quelles propriétés CSS sont accélérées par le GPU et les plus adaptées à des animations fluides ?
2. Quelle valeur d'images par seconde (FPS) correspond à une animation fluide ?
Voici 2 des 4 questions de cette leçon. Réponds aux autres dans le jeu.
Tâches pratiques dans le jeu
- Tri vertical
Classe ces façons d'animer, de la plus performante (GPU) à la plus lente (reflow) :