Modern websites concurreren om aandacht met steeds indrukwekkendere visuals. Parallax-hero-secties strekken zich diep uit in de viewport. Carrousels scrollen eindeloos door. Achtergrondvideo's spelen automatisch af achter aanmeldformulieren. Deze patronen ogen gepolijst en boeiend in een designportfolio. Voor een deel van je publiek zijn ze een fysieke trigger.
Mensen met vestibulaire stoornissen ervaren misselijkheid, duizeligheid of migraine wanneer ze worden geconfronteerd met grote gebieden met continue beweging. Om hen te beschermen, bevat elk groot besturingssysteem nu een "Reduce Motion"-instelling voor toegankelijkheid. Webbrowsers maken die voorkeur beschikbaar via de prefers-reduced-motion media query. React-ontwikkelaars die dit netjes willen respecteren, kunnen de useReducedMotion hook van @reactuses/core gebruiken. Deze leest de OS-voorkeur uit als een boolean, wordt live bijgewerkt als de gebruiker van gedachten verandert, en handelt server-side rendering af zonder vast te lopen.
Waarom handgemaakte oplossingen falen
Je zou de voorkeur zelf kunnen opvragen met window.matchMedia('(prefers-reduced-motion: reduce)'). Veel ontwikkelaars doen dit, en velen leveren subtiele bugs op.
Ten eerste kun je gemakkelijk de 'change listener' vergeten. De initiële query wordt één keer uitgevoerd wanneer de component wordt gemount. Als een gebruiker je app opent en vervolgens 'Reduce Motion' in de systeeminstellingen aan- of uitzet omdat een carrousel hen misselijk maakt, hoort je component de update nooit. Het media query-object ondersteunt addEventListener, maar het correct koppelen, verwijderen bij het unmounten en het polyfillen van de verouderde addListener-syntax is boilerplate-code die uitnodigt tot copy-paste-fouten.
Ten tweede bestaat window niet tijdens SSR. Als je app op de server wordt gerenderd, veroorzaakt een naïeve matchMedia-aanroep een reference error en stopt het renderen. Je eindigt met het omwikkelen van de check in typeof window !== 'undefined' guards, waarbij je de standaardwaarde gokt en hoopt dat de client-hydratatie overeenkomt.
Ten derde verandert het herhalen van die logica in elke geanimeerde component in onderhoudsschuld. De ene teamgenoot schrijft de listener op de ene manier, een ander slaat hem volledig over, en een derde hardcodeert een standaardwaarde die beweging bevordert. Een hook centraliseert de chaos.
useReducedMotion lost alle drie de problemen op. Het geeft een eenvoudige boolean terug. Het voert veilig een 'no-op' uit op de server. Het koppelt de listener automatisch en ruimt deze ook weer op.
Drie manieren om het in de praktijk te brengen
Zodra je de boolean hebt, heb je een strategie nodig om er actie op te ondernemen. Hier zijn drie patronen die schalen van een enkele component naar een volledige applicatie.
1. CSS-classes beperken om verspilde arbeid te voorkomen
De meest directe aanpak is om te voorkomen dat zware JavaScript-animatielussen überhaupt starten. Stel je voor dat je een parallax-afbeeldingscomponent hebt die normaal gesproken luistert naar scroll-events en lagen verplaatst binnen een requestAnimationFrame-lus. In plaats van die logica uit te voeren en vervolgens het visuele resultaat te onderdrukken, controleer je eerst useReducedMotion.
Als de hook true teruggeeft, render je de component met een statische variant-class en sla je de useEffect over die de scroll-listeners koppelt. De browser hoeft minder werk te verrichten. Gebruikers met bewegingsgevoeligheid zien een stilstaande afbeelding. Iedereen anders krijgt de bewegende lagen te zien. Omdat de animatiecode nooit wordt geïnitialiseerd, bespaar je onderweg CPU en batterij.
2. Voed het direct aan animatielibrariën
Als je een bibliotheek zoals Framer Motion gebruikt, sluit de hook direct aan op je prop-definities. Motion-componenten accepteren configuratie-objecten voor variants, transitions en gestures. Je kunt de boolean van useReducedMotion gebruiken om voorwaardelijk duration: 0 in te stellen op transitions, of
