Utiliser prefers-reduced-motion pour des animations accessibles
Certains utilisateurs ressentent des étourdissements, des nausées ou de la désorientation face aux interfaces animées. La fonctionnalité média CSS prefers-reduced-motion vous permet de détecter leur préférence système et d’y répondre avec un mouvement plus sûr — sans dépouiller votre interface de tout son raffinement visuel. Cet article aborde l’implémentation pratique en CSS et JavaScript à travers des patterns de composants courants.
Points clés à retenir
prefers-reduced-motionest une media query CSS qui lit un paramètre d’accessibilité au niveau du système d’exploitation, avec deux valeurs :reduceetno-preference.- L’objectif est de réduire ou remplacer les mouvements non essentiels, et non d’éliminer complètement les animations — les fondus d’opacité et les durées raccourcies restent des alternatives plus sûres.
- Utilisez l’approche CSS progressive (opt-in) pour protéger les utilisateurs qui n’ont pas explicitement défini de préférence, mais qui peuvent tout de même être sensibles au mouvement.
- Pour les animations pilotées par JavaScript,
window.matchMediaet les listeners comme le hookuseReducedMotion()de Motion maintiennent le comportement synchronisé avec les changements du système. - Le panneau Rendering de Chrome DevTools émule cette préférence, ce qui vous permet de tester sans modifier les paramètres de votre OS.
prefers-reduced-motionpeut aider à respecter le WCAG 2.3.3, mais pas le contenu en lecture automatique ou en boucle, qui nécessite toujours des contrôles de pause explicites conformément au WCAG 2.2.2.
Ce que fait réellement prefers-reduced-motion
prefers-reduced-motion est une media query CSS mature et largement supportée — ce n’est pas une nouvelle API. Elle lit un paramètre d’accessibilité au niveau du système que l’utilisateur a activé sur son OS (macOS, Windows, iOS, Android, Linux). Les deux valeurs sont :
reduce— l’utilisateur a demandé moins de mouvementno-preference— aucune préférence n’a été définie
À noter : @media (prefers-reduced-motion) est l’équivalent abrégé de @media (prefers-reduced-motion: reduce).
La page MDN Web Docs couvre la syntaxe complète et le tableau de compatibilité des navigateurs, tandis que Can I use confirme un large support à travers les moteurs modernes.
Le bon modèle mental : réduire, ne pas supprimer
Une erreur courante consiste à traiter cette fonctionnalité comme un interrupteur d’arrêt pour toute animation. Ce n’est pas l’objectif. Les recommandations — y compris WCAG 2.3.3 (« Animation issue d’interactions », Niveau AAA) — visent à réduire ou remplacer les mouvements non essentiels, en particulier :
- Les mouvements à grande échelle (parallaxe, zoom, panneaux glissants)
- Les éléments en rotation
- Les animations déclenchées au défilement qui déplacent du contenu à travers la fenêtre d’affichage
Les fondus d’opacité, les transitions de couleur et les durées raccourcies sont généralement des alternatives plus sûres. Une modale qui apparaît en fondu plutôt que de surgir depuis le bas communique toujours un changement d’état sans déclencher d’inconfort vestibulaire.
Implémentation CSS : deux approches
Défensive (opt-out) : Définissez les styles animés par défaut, puis surchargez-les à l’intérieur de la media query.
.modal {
transform: translateY(20px);
opacity: 0;
transition: transform 300ms ease, opacity 300ms ease;
}
@media (prefers-reduced-motion: reduce) {
.modal {
transform: none;
transition: opacity 200ms ease;
}
}
Progressive (opt-in) : Définissez les styles statiques par défaut, et n’ajoutez le mouvement que lorsque l’utilisateur ne s’y est pas opposé.
/* Statique par défaut */
.modal {
opacity: 0;
transition: opacity 200ms ease;
}
@media (prefers-reduced-motion: no-preference) {
.modal {
transform: translateY(20px);
transition: transform 300ms ease, opacity 300ms ease;
}
}
L’approche progressive est plus sûre pour les utilisateurs qui n’ont pas défini de préférence, mais qui peuvent tout de même être sensibles au mouvement.
Les propriétés personnalisées CSS rendent cette approche évolutive dans une grande base de code :
:root {
--duration: 300ms;
--easing: ease;
}
@media (prefers-reduced-motion: reduce) {
:root {
--duration: 0.01ms;
}
}
.drawer {
transition: transform var(--duration) var(--easing);
}
Détecter la préférence en JavaScript
Pour les animations pilotées par JS, utilisez window.matchMedia :
const prefersReduced = window.matchMedia('(prefers-reduced-motion: reduce)');
if (prefersReduced.matches) {
// ignorer ou simplifier l'animation
}
// Réagir aux changements de préférence en temps réel (ex. : l'utilisateur modifie le paramètre OS)
prefersReduced.addEventListener('change', (e) => {
if (e.matches) {
// mettre en pause ou remplacer les animations
}
});
C’est utile pour les carrousels, les effets déclenchés au défilement, ou toute animation pilotée en dehors du CSS.
Discover how at OpenReplay.com.
Bibliothèques d’animation : Framer Motion et Motion.dev
Si vous utilisez Motion for React (la bibliothèque que beaucoup appellent encore Framer Motion — sa documentation se trouve désormais sur Motion.dev), le hook useReducedMotion() gère cela proprement :
import { motion } from "motion/react";
import { useReducedMotion } from "motion/react";
function Drawer({ isOpen }) {
const reduce = useReducedMotion();
return (
<motion.div
animate={{ x: isOpen ? 0 : -300, opacity: isOpen ? 1 : 0 }}
transition={reduce ? { duration: 0 } : { duration: 0.3 }}
/>
);
}
Le hook lit la préférence système de manière réactive, il reste donc synchronisé si l’utilisateur modifie son paramètre OS en cours de session.
Tester avec Chrome DevTools
Vous n’avez pas besoin de modifier les paramètres de votre OS pour tester. Dans Chrome DevTools :
- Ouvrez DevTools → onglet Rendering (via le menu à trois points → More tools → Rendering)
- Trouvez « Emulate CSS media feature prefers-reduced-motion »
- Réglez-le sur
reduce
Votre page réagira immédiatement, ce qui vous permet de vérifier chaque composant animé sans toucher aux préférences système.
Une note sur la couverture WCAG
prefers-reduced-motion peut aider à respecter le WCAG 2.3.3, mais il ne couvre pas tout. Les vidéos en lecture automatique, les GIF en boucle et le contenu en mouvement continu peuvent encore nécessiter des contrôles explicites de pause/arrêt conformément au WCAG 2.2.2 (« Mettre en pause, arrêter, masquer »). La media query gère bien les animations déclenchées par interaction — les mouvements d’arrière-plan persistants nécessitent une solution distincte.
Conclusion pratique
Auditez vos composants animés — modales, tiroirs, effets de survol, carrousels, transitions de page — et décidez pour chacun s’il faut réduire la durée, remplacer le mouvement par de l’opacité, ou ignorer complètement l’animation. Utilisez les propriétés personnalisées CSS pour centraliser la logique, matchMedia lorsque JavaScript contrôle l’animation, et Chrome DevTools pour vérifier sans modifier votre OS.
Conclusion
Respecter prefers-reduced-motion est l’un des gains d’accessibilité les moins coûteux et les plus impactants disponibles pour les développeurs front-end. La technologie est stable, le support des navigateurs est excellent, et les patterns d’implémentation sont simples à travers CSS, JavaScript et les bibliothèques d’animation modernes. Le vrai travail consiste à changer votre modèle mental : l’animation devient une couche à atténuer pour les utilisateurs sensibles plutôt qu’une fonctionnalité à désactiver. Intégrez cette habitude à chaque composant que vous livrez.
FAQ
Régler la durée à une valeur très faible comme 0.01ms est souvent préférable à zéro. Cela préserve l'événement transitionend, de sorte que la logique JavaScript qui écoute la fin d'une animation continue de se déclencher. Un véritable zéro peut court-circuiter l'événement dans certains navigateurs et casser les machines à états qui en dépendent. Le résultat visuel est identique à un changement instantané.
Cela peut être le cas, mais le comportement diffère selon les navigateurs et les implémentations. Une approche plus sûre consiste à encapsuler le défilement fluide CSS dans @media (prefers-reduced-motion: no-preference) afin que les utilisateurs en mode réduit reçoivent toujours un défilement instantané. Si vous implémentez une animation de défilement personnalisée en JavaScript, vous devriez également vérifier la préférence manuellement et revenir à un défilement instantané en utilisant window.scrollTo avec behavior réglé sur auto.
Non. Les animations raccourcies ou ignorées améliorent généralement la réactivité perçue, car les utilisateurs voient le contenu se stabiliser plus rapidement. Interaction to Next Paint en profite souvent, car les transitions ne retardent plus le retour visuel. La seule réserve est de supprimer les animations qui communiquaient des changements d'état — remplacez-les par des fondus d'opacité ou des changements de couleur afin que l'interface reste réactive plutôt qu'abrupte.
Oui, et c'est une bonne pratique pour les utilisateurs sur des appareils partagés ou ceux qui n'ont pas découvert l'option OS. Stockez la préférence dans localStorage et combinez-la avec le résultat de la media query en utilisant un OU logique. De cette façon, le paramètre OS ou le bouton dans l'application peut déclencher la réduction du mouvement, offrant aux utilisateurs un contrôle maximal sans outrepasser leur préférence système.
Truly understand users experience
See every user interaction, feel every frustration and track all hesitations with OpenReplay — the open-source digital experience platform. It can be self-hosted in minutes, giving you complete control over your customer data. . Check our GitHub repo and join the thousands of developers in our community..