Retour au cours

frontend / css

Transitions et animations

Leçon 131 exercice

Explication

Ce que vous allez apprendre

  • Distinguer clairement transition (un changement entre deux états) et @keyframes/animation (une séquence autonome)
  • Éviter le piège de performance de transition: all en listant explicitement les propriétés animées
  • Contrôler la vitesse perçue d'une animation avec les fonctions de timing (ease, cubic-bezier, etc.)
  • Empêcher le "flash" de retour à l'état initial grâce à animation-fill-mode
  • Créer un effet de cascade sur une liste d'éléments avec animation-delay
  • Piloter la lecture d'une animation en JavaScript via animation-play-state

Dans quel contexte ?

Une équipe travaille sur le tableau de bord d'une application de gestion de commandes. Quand un utilisateur clique sur "Valider la commande", le bouton doit changer de couleur en douceur (une transition), pendant qu'une icône de succès pulse doucement pour attirer l'œil (une animation en boucle). Sans ces deux outils bien maîtrisés, l'interface paraît soit figée et brutale, soit distrayante et mal maîtrisée côté performance.

Étape 1 : le mouvement aide à comprendre

Une interface qui change d'état brutalement est plus difficile à suivre pour l'œil qu'une transition fluide. L'animation CSS n'est donc pas qu'un effet décoratif : elle aide l'utilisateur à comprendre CE QUI a changé.

Étape 2 : deux outils, une confusion fréquente

Il existe une confusion classique entre transition et @keyframes/animation. Une transition anime le passage entre DEUX états déclenchés par un événement, comme :hover — elle a besoin d'un changement pour se déclencher.

OutilDéclenchementCas d'usage typique
transitionun changement d'état (:hover, ajout d'une classe)survol de bouton, ouverture d'un menu
@keyframes + animationautonome, dès l'application de la règlespinner de chargement, pulsation de badge

Étape 3 : et pour une séquence autonome ?

Une animation basée sur @keyframes définit, elle, une séquence AUTONOME avec plusieurs étapes intermédiaires, capable de se lancer d'elle-même sans attendre d'interaction — un chargement en boucle, une pulsation de notification.

Étape 4 : le piège de transition: all

Une fois cette distinction claire, voici un piège courant : transition: all 0.3s semble pratique, mais force le navigateur à surveiller CHAQUE propriété CSS en continu.

Piège fréquent

transition: all peut animer des propriétés que vous n'aviez pas prévues (par exemple une height qui change à cause d'un contenu dynamique), créant des effets visuels inattendus. Listez toujours les propriétés explicitement : transition: background 0.3s, transform 0.3s.

Étape 5 : pourquoi c'est un problème en pratique

Cela consomme plus de ressources qu'une liste explicite, et peut créer des animations non désirées sur des propriétés qu'on ne pensait pas concernées. Lister précisément les propriétés animées reste la bonne pratique.

Étape 6 : le flash désagréable après une animation

Il reste un dernier piège très fréquent : sans précaution, une animation revient à son état de départ dès qu'elle se termine, créant un flash visuel disgracieux.

La solution à ce flash

Bonne pratique

Ajoutez toujours animation-fill-mode: forwards (ou both) sur une animation d'apparition : sans cela, l'élément redevient invisible une fraction de seconde après la fin de l'animation, ce qui donne une impression de bug.

animation-fill-mode: forwards (ou both) corrige ce comportement en conservant l'état final de l'animation une fois celle-ci terminée.

Et ensuite ?

Une fois transitions et animations maîtrisées, la prochaine étape ajoute une dimension supplémentaire : les transformations 2D et 3D.

Commandes & code

Transitions et animations

Animer des changements d'état simples avec transition, des séquences complexes avec @keyframes.

css
/* transition : anime un changement de valeur entre deux états */
.bouton {
    background: #2563eb;
    transform: scale(1);
    transition: background 0.2s ease, transform 0.15s ease-out;
}
.bouton:hover {
    background: #1d4ed8;
    transform: scale(1.03);
}

/* transition: all -> pratique mais coûteux (surveille TOUTES les propriétés,
   y compris celles qu'on ne voulait pas animer) : à éviter en production */
.mauvais { transition: all 0.3s; }
.bon { transition: background 0.3s, transform 0.3s; }

/* Fonctions de timing */
.rapide-au-debut  { transition-timing-function: ease-out; }
.rapide-a-la-fin  { transition-timing-function: ease-in; }
.symetrique       { transition-timing-function: ease-in-out; }
.lineaire         { transition-timing-function: linear; }
.personnalise     { transition-timing-function: cubic-bezier(0.34, 1.56, 0.64, 1); } /* effet "rebond" */
css
/* @keyframes : séquence à plusieurs étapes, indépendante d'un état déclenché */
@keyframes apparition {
    from {
        opacity: 0;
        transform: translateY(12px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

@keyframes pulsation {
    0%   { transform: scale(1); }
    50%  { transform: scale(1.08); }
    100% { transform: scale(1); }
}

.carte {
    animation: apparition 0.4s ease-out both;
    /* both : applique le style du 1er keyframe avant le début,
       et garde celui du dernier après la fin */
}

.badge-notification {
    animation: pulsation 1.5s ease-in-out infinite;
}

/* Décalage en cascade pour une liste d'éléments */
.liste li {
    animation: apparition 0.4s ease-out both;
}
.liste li:nth-child(1) { animation-delay: 0.05s; }
.liste li:nth-child(2) { animation-delay: 0.1s; }
.liste li:nth-child(3) { animation-delay: 0.15s; }
css
/* Contrôle fin d'une animation */
.element {
    animation-name: pulsation;
    animation-duration: 2s;
    animation-timing-function: ease-in-out;
    animation-delay: 0.5s;
    animation-iteration-count: 3;      /* ou "infinite" */
    animation-direction: alternate;    /* aller-retour à chaque itération */
    animation-fill-mode: forwards;     /* garde l'état final après la fin */
    animation-play-state: paused;      /* pilotable en JS, ex: au survol */
}

.element:hover {
    animation-play-state: running;
}

Résumé

  • transition anime un changement d'état ; @keyframes + animation anime une séquence autonome.
  • Lister explicitement les propriétés animées (jamais transition: all) pour la lisibilité et la performance.
  • animation-fill-mode: both/forwards évite le "flash" de retour à l'état initial après une animation.
  • animation-delay décalé par élément crée un effet de cascade sans JavaScript.

Exercices pratiques

1 disponible
1

Mission : un badge de succès qui clignote et disparaît trop tôt

Objectif : Corriger un usage risqué de transition: all et un flash de fin d'animation sur un badge de validation de commande.

Contexte

Sur commande.css, le bouton .btn-valider utilise transition: all 0.3s; pour animer sa couleur au survol. Une fois la commande validée, un badge .badge-succes reçoit dynamiquement la classe .apparait, qui déclenche animation: apparition 0.4s ease-out; (sans autre réglage d'animation). Deux bugs sont observés : la hauteur du bouton "saute" visiblement pendant le survol à cause d'un changement de padding lié au JS, et le badge de succès clignote en redevenant invisible juste après son apparition.

Résoudre l’exercice →