Mouvement UX (UX motion)
Appliquez ces règles lors de la conception et de l'écriture de l'interaction. Inspectez d'abord les jetons de mouvement du projet : les fichiers AGENTS.md, CLAUDE.md, les fichiers de jetons et les docs de conception remplacent les valeurs par défaut ci-dessous.
Cœur toujours actif
- Décision par défaut : l'interface utilisateur fonctionnelle se situe généralement dans une bande de 120 à 180 ms. Les jetons du projet l'emportent.
- Animez pour la continuité spatiale, le changement d'état, le retour d'information sur une saisie, ou pour éviter une apparition brutale.
- Préférez les transitions nommées
transformetopacity. N'utilisez jamaistransition: all. - Les surfaces qui apparaissent doivent décélérer ; les surfaces qui disparaissent doivent accélérer. Les sorties peuvent être plus courtes.
- Commencez les surfaces mises à l'échelle près de
scale(0.96), jamais à partir descale(0). - Maintenez le mouvement remplaçable sous
prefers-reduced-motion: reduce; préservez la compréhension et l'accès au clavier. - Capturez le pointeur pour les glissés, protégez les touches secondaires et testez les gestes sur du matériel.
- Avant d'écrire du mouvement ou de toucher à une superposition courante, lisez ce fichier en entier. Utilisez
REFERENCE.mduniquement pour les chemins de détourage, la 3D, l'API WAAPI ou les analyses de performance approfondies.
1. Décidez si le mouvement est justifié
Utilisez la fréquence d'exposition comme contrainte : les actions répétées constamment doivent être instantanées ou presque ; les surfaces occasionnelles peuvent établir une continuité spatiale ; les moments rares et explicatifs peuvent avoir plus de personnalité. Le mouvement doit clarifier un changement, accuser réception d'une entrée, préserver un emplacement ou éviter une apparition brutale. S'il ne fait rien de tout cela, supprimez-le. Ne faites pas attendre un raccourci clavier pour un mouvement décoratif.
2. Choisissez une durée
La bande 120–180 ms est une décision par défaut : elle est intentionnellement plus serrée que la plage courte3 (150 ms), courte4 (200 ms) et la plage de transition standard (250–400 ms) publiées par Material 3. Elle exprime une préférence contre une interface utilisateur fonctionnelle lente, et non une exigence d'accessibilité ou de plateforme publiée.
| Surface | Point de départ |
|---|---|
| Retour de pression (feedback press) | 100–140 ms |
| Infobulle (tooltip) ou petit popover | 120–160 ms |
| Menu ou liste déroulante (dropdown) | 140–180 ms |
| Fenêtre modale (modal) | 180 ms |
| Feuille (sheet) | 180 ms ; jusqu'à 250 ms lorsqu'elle parcourt la majeure partie de la fenêtre d'affichage |
Utilisez la valeur la plus courte pour les sorties. Ce sont des valeurs par défaut, pas des surcharges pour les jetons du produit.
3. Choisissez un assouplissement (easing)
Une surface qui entre doit arriver avec une emphase qui s'installe (décélère) ; une sortie doit s'effacer rapidement (accélère). Material 3 nomme ces directions explicitement :
:root {
--ease-standard: cubic-bezier(0.2, 0, 0, 1);
--ease-enter: cubic-bezier(0.05, 0.7, 0.1, 1); /* emphasized-decelerate */
--ease-exit: cubic-bezier(0.3, 0, 0.8, 0.15); /* emphasized-accelerate */
}
Utilisez linear uniquement pour une progression de type temporelle. Utilisez une courbe ease-in-out pour un état qui traverse un point médian délibéré. Évitez de choisir une courbe uniquement par son nom : inspectez la forme tracée et la direction du déplacement.
4. Gardez le rendu léger
Préférez transform et opacity, qui peuvent rester sur le compositeur. Nommez les propriétés et évitez d'impliquer la mise en page dans l'animation. Évitez d'animer top, left, width, height, la marge (margin) ou le remplissage (padding) à moins que le changement de mise en page ne soit le but et que le coût soit accepté. Pour la hauteur intrinsèque, un wrapper peut faire la transition grid-template-rows: 0fr vers 1fr, avec un wrapper intérieur min-height: 0 masqué par overflow: hidden. Cela effectue toujours une mise en page ; profilez-le plutôt que de le traiter comme un raccourci du compositeur uniquement. Utilisez will-change tardivement, brièvement, et seulement après que le profilage montre qu'il aide ; les couches consomment des ressources.
5. Rendez les états corrects
- Donnez un retour visible aux éléments pressables ; utilisez un état de couleur, de bordure ou d'ombre existant, ou un petit
scale(0.98)lorsque cela convient. N'écrasez pas une transformation de positionnement. - Préservez le focus visible, l'activation au clavier et le comportement désactivé. L'animation ne doit pas retarder le placement du focus, la gestion de la touche Échap ou les mises à jour d'état sémantique.
- Les popovers, menus et infobullies grandissent à partir d'un point d'ancrage via
transform-origin; les fenêtres modales centrées grandissent à partir du centre. Gardez l'origine stable pendant que l'état change. - Préférez les transitions pour les états qui peuvent être déclenchés à nouveau. Utilisez des keyframes pour un événement autonome.
- Limitez les effets au survol uniquement avec
@media (hover: hover) and (pointer: fine). - Pour un élément qui entre, utilisez
@starting-stylelà où c'est pris en charge, ou un état monté qui rend le style initial observable avant la transition.
6. Mouvement réduit signifie un remplacement
Le réglage prefers-reduced-motion couvre le mouvement supprimé, réduit ou remplacé ; le panoramique et le zoom à grande échelle peuvent être des déclencheurs vestibulaires. Remplacez le déplacement et l'échelle par des changements d'opacité et de couleur là où ceux-ci expliquent encore l'état. Gardez les changements de focus, de chargement et de visibilité compréhensibles. Ne faites pas disparaître un élément simplement parce que l'utilisateur a demandé moins de mouvement. Honorez cette préférence dans les animations pilotées par JavaScript ainsi que par CSS, y compris les changements de préférence pendant que la page est ouverte. Ne dépendez pas d'un événement transitionend pour terminer un changement d'état essentiel : la transition peut être désactivée ou annulée. Limitez les surcharges au composant affecté au lieu de forcer globalement chaque animation à une durée minuscule.
7. Gestes
Appelez setPointerCapture() lorsqu'un glissé commence : les événements de pointeur ultérieurs continueront alors à cibler l'élément de capture jusqu'au relâchement. Fermez (dismiss) sur une règle de vélocité ou distance ajustée ; il n'y a pas de constante de flick universelle, donc calibrez-la sur l'appareil réel. Maintenez le mouvement borné avec un amortissement (damping) au lieu d'un bord dur. Ignorez les points de contact supplémentaires une fois qu'un geste possède le pointeur. Laissez l'utilisateur inverser un geste en cours. Gérez pointercancel et lostpointercapture en effaçant l'état de glissé. Choisissez touch-action pour l'axe du geste sans bloquer inutilement le défilement de la page ; fournissez un bouton ou un équivalent clavier.
8. Gérez l'interruption et les ressorts (springs)
Une ouverture/fermeture/réouverture rapide doit aboutir au dernier état demandé. Reciblez à partir de l'état visuel actuel plutôt que de rejouer depuis le début. Annulez les callbacks, écouteurs et animations obsolètes lors du remplacement ou du démontage ; une ancienne sortie ne doit pas supprimer une surface nouvellement rouverte. Gardez le contenu caché ou en cours de sortie hors de la navigation au clavier selon le cycle de vie du focus du composant.
Utilisez un ressort (spring) lorsque la manipulation directe ou la continuité en bénéficie, en respectant la bibliothèque du projet. Les paramètres de ressort varient entre les moteurs : ne copiez pas aveuglément les valeurs de rigidité et d'amortissement. Réglez le temps d'établissement et le dépassement (overshoot) sur le composant réel ; évitez le rebond sur les surfaces riches en texte et désactivez le déplacement en mouvement réduit.
9. Vérifiez avant de déclarer terminé
Rejouez à une vitesse 4× plus lente et vérifiez que les propriétés se terminent ensemble et proviennent du bon endroit. Basculez rapidement pour exposer les accrocs. Émulez le mouvement réduit dans les DevTools. Exercez un glissé au-delà de son bord, annulez-le, ajoutez un deuxième contact et testez sur un appareil physique. Pour les valeurs d'animation calculées à l'exécution, consultez REFERENCE.md. Indiquez quelles vérifications ont été réellement effectuées et lesquelles nécessitent un navigateur ou un appareil physique ; la seule revue de code ne peut pas établir la fluidité perçue.
Examiner la sortie (output)
Lors de l'audit du code, rapportez un tableau concis, le plus grave en premier :
| Fichier:ligne | Maintenant | Remplacer par | Pourquoi |
|---|---|---|---|
Menu.tsx:18 | transition: all 300ms | propriétés nommées et jetons du projet | évite l'animation de mise en page accidentelle |
Ne rapportez que les résultats visibles dans le code. Si la diff est propre, dites-le plutôt que d'inventer des résultats.
Organisé par mad7droid.