Rispettare le preferenze di movimento degli utenti

Pubblicato: 2022-03-10
Riepilogo rapido ↬ La query multimediale prefers-reduced-motion ha un eccellente supporto in tutti i browser moderni risalenti a un paio d'anni fa. In questo articolo, Michelle Barker spiega perché non c'è motivo di non usarlo oggi per rendere i tuoi siti più accessibili.

Quando si lavora con il movimento sul Web, è importante considerare che non tutti lo sperimentano allo stesso modo. Ciò che potrebbe sembrare liscio e liscio per alcuni potrebbe essere fastidioso o distrarre gli altri o, peggio, indurre sentimenti di malattia o addirittura causare convulsioni. I siti Web con molto movimento potrebbero anche avere un impatto maggiore sulla durata della batteria dei dispositivi mobili o causare l'utilizzo di più dati (la riproduzione automatica dei video, ad esempio, richiederà più dati di un utente rispetto a un'immagine statica). Questi sono solo alcuni dei motivi per cui i siti con movimento pesante potrebbero non essere desiderabili per tutti.

La maggior parte dei nuovi sistemi operativi consente all'utente di impostare le proprie preferenze di movimento nelle impostazioni a livello di sistema. La media query prefers-reduced-motion (parte della specifica Level 5 Media Query) ci consente di rilevare le preferenze di movimento a livello di sistema degli utenti e di applicare stili CSS che le rispettano.

Le due opzioni per prefers-reduced-motion sono reduce o no-preference . Possiamo usarlo nel modo seguente nel nostro CSS per disattivare l'animazione di un elemento se l'utente ha esplicitamente impostato una preferenza per il movimento ridotto :

 .some-element { animation: bounce 1200ms; } @media (prefers-reduced-motion: reduce) { .some-element { animation: none; } }

Al contrario, potremmo impostare l'animazione solo se l'utente non ha preferenze di movimento. Questo ha il vantaggio di ridurre la quantità di codice che dobbiamo scrivere e significa che è meno probabile che dimenticheremo di soddisfare le preferenze di movimento degli utenti:

 @media (prefers-reduced-motion: no-preference) { .some-element { animation: bounce 1200ms; } }

Un ulteriore vantaggio è che i browser meno recenti che non supportano prefers-reduced-motion ignoreranno la regola e visualizzeranno solo il nostro elemento originale privo di movimento.

Quale regola?

A differenza delle media query min-width e max-width , in cui il consenso più o meno stabilito è mobile-first (quindi favorendo min-width ), non esiste un unico modo "giusto" per scrivere i tuoi stili a movimento ridotto. Tendo a favorire il secondo esempio (applicando animazioni solo se prefers-reduced-motion: no-preference valuta vero), per i motivi sopra elencati. Tatiana Mac ha scritto questo eccellente articolo che copre alcuni degli approcci che gli sviluppatori potrebbero prendere in considerazione, oltre a molti altri ottimi punti, comprese le domande chiave da porre quando si progetta con il movimento sul Web.

Come sempre, la comunicazione del team e una strategia coerente sono fondamentali per garantire che tutte le basi siano coperte quando si tratta di accessibilità al web.

Altro dopo il salto! Continua a leggere sotto ↓

Uso pratico: l'applicazione del comportamento di scorrimento prefers-reduced-motion

prefers-reduced-motion ha molte applicazioni oltre all'applicazione (o non applicazione) di animazioni o transizioni di fotogrammi chiave. Un esempio è lo scorrimento fluido. Se impostiamo scroll-behaviour: smooth sul nostro elemento html , quando un utente fa clic su un link di ancoraggio in-page verrà fatto scorrere senza problemi nella posizione appropriata sulla pagina ( attualmente non supportata in Safari ):

 html { scroll-behavior: smooth; }

Sfortunatamente, in CSS non abbiamo molto controllo su quel comportamento in questo momento. Se abbiamo una lunga pagina di contenuti, la pagina scorre molto velocemente, il che può essere un'esperienza piuttosto spiacevole per qualcuno con sensibilità al movimento. Avvolgendolo in una query multimediale, possiamo impedire che tale comportamento venga applicato nei casi in cui l'utente ha una preferenza reduced-motion :

 @media (prefers-reduced-motion: no-preference) { html { scroll-behavior: smooth; } }

Soddisfare le preferenze di movimento in Javascript

A volte è necessario applicare il movimento in JavaScript anziché in CSS. Allo stesso modo, possiamo rilevare le preferenze di movimento di un utente con JS, utilizzando matchMedia . Vediamo come possiamo implementare condizionatamente un comportamento di scorrimento regolare nel nostro codice JS:

 /* Set the media query */ const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)') button.addEventListener('click', () => { /* If the media query matches, set scroll behavior variable to 'auto', otherwise set it to 'smooth' */ const behavior = prefersReducedMotion.matches ? 'auto' : 'smooth' /* When the button is clicked, the user will be scrolled to the top */ window.scrollTo({ x: 0, y: 0, behavior }) })

Lo stesso principio può essere utilizzato per rilevare se implementare UI ricche di movimento con librerie JS o anche se caricare le librerie stesse.

Nel frammento di codice seguente, la funzione ritorna in anticipo se l'utente preferisce il movimento ridotto, evitando l'importazione non necessaria di una grande dipendenza, un vantaggio in termini di prestazioni per l'utente. Se non hanno alcuna preferenza di movimento impostata, possiamo importare dinamicamente la libreria di animazioni Greensock e inizializzare le nostre animazioni.

 const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)') const loadGSAPAndInitAnimations = () => { /* If user prefers reduced motion, do nothing */ if (prefersReducedMotion.matches) return /* Otherwise, import the GSAP module and initialize animations */ import('gsap').then((object) => { const gsap = object.default /* Initialize animations with GSAP here */ }) } loadGSAPAndInitAnimations()

reduced-motion non significa nessun movimento

Quando si applica lo stile per le preferenze di movimento ridotte, è importante fornire comunque all'utente indicatori significativi e accessibili di quando si è verificata un'azione. Ad esempio, quando si disattiva uno stato al passaggio del mouse che distrae o fa molto movimento per gli utenti che preferiscono il movimento ridotto, dobbiamo fare attenzione a fornire uno stile alternativo chiaro per quando l'utente è in bilico sull'elemento.

La demo seguente mostra una transizione elaborata quando l'utente passa con il mouse o si concentra su un elemento della galleria se non ha impostato alcuna preferenza di movimento. Se preferiscono il movimento ridotto, la transizione è più sottile, ma indica ancora chiaramente lo stato al passaggio del mouse:

Guarda la penna [Galleria con prefers-reduced-motion](https://codepen.io/smashingmag/pen/KKvMqaL) di Michelle Barker.

Guarda la Pen Gallery con i preferiti in movimento ridotto di Michelle Barker.

Il movimento ridotto non significa necessariamente anche rimuovere tutte le trasformazioni dalla nostra pagina web. Ad esempio, è improbabile che un pulsante con una piccola icona a freccia che si sposta di alcuni pixel al passaggio del mouse causi problemi a chi preferisce un'esperienza a movimento ridotto e fornisce un indicatore più utile di un cambiamento di stato rispetto al solo colore.

A volte vedo sviluppatori che applicano stili di movimento ridotto nel modo seguente, che elimina tutte le transizioni e le animazioni su tutti gli elementi:

 @media screen and (prefers-reduced-motion: reduce) { * { animation: none !important; transition: none !important; scroll-behavior: auto !important; } }

Questo è probabilmente meglio che ignorare le preferenze di movimento degli utenti, ma non ci consente di personalizzare facilmente gli elementi per fornire transizioni più sottili quando necessario.

Nel seguente frammento di codice, abbiamo un pulsante che aumenta di scala al passaggio del mouse . Stiamo effettuando la transizione dei colori e della scala, ma gli utenti con una preferenza per il movimento ridotto non otterranno alcuna transizione:

 button { background-color: hotpink; transition: color 300ms, background-color 300ms, transform 500ms cubic-bezier(.44, .23, .47, 1.27); } button:hover, button:focus { background-color: darkviolet; color: white; transform: scale(1.2); } @media screen and (prefers-reduced-motion: reduce) { * { animation: none !important; transition: none !important; scroll-behavior: auto !important; } button { /* Even though we would still like to transition the colors of our button, the following rule will have no effect */ transition: color 200ms, background-color 200ms; } button:hover, button:focus { /* Preventing the button scaling on hover */ transform: scale(1); } }

Dai un'occhiata a questa demo per vedere l'effetto. Questo forse non è l'ideale, poiché l'improvviso cambio di colore senza una transizione potrebbe sembrare più stridente di una transizione di un paio di centinaia di millisecondi. Questo è uno dei motivi per cui, nel complesso, preferisco generalmente lo stile per il movimento ridotto caso per caso.

Se sei interessato, questa è la stessa demo modificata per consentire la personalizzazione della transizione quando necessario. Utilizza una proprietà personalizzata per la durata della transizione, che ci consente di attivare e disattivare la transizione della scala senza dover riscrivere l'intera dichiarazione.

Quando è meglio rimuovere l'animazione

Eric Bailey solleva il punto che "non tutti i dispositivi in ​​grado di accedere al Web possono anche eseguire il rendering dell'animazione o il rendering dell'animazione senza intoppi" nel suo articolo, "La rivisitazione preferisce il movimento ridotto, la query multimediale con movimento ridotto". Per i dispositivi con una frequenza di aggiornamento bassa, che può causare animazioni janky, potrebbe infatti essere preferibile rimuovere l'animazione . La funzione di update del supporto può essere utilizzata per determinare ciò:

 @media screen and (prefers-reduced-motion: reduce), (update: slow) { * { animation-duration: 0.001ms !important; animation-iteration-count: 1 !important; transition-duration: 0.001ms !important; } }

Assicurati di leggere l'articolo completo per i consigli di Eric, poiché è una persona di prim'ordine da seguire nel campo dell'accessibilità.

La somma di tutte le parti

È importante tenere a mente il design generale della pagina quando ci si concentra così strettamente sul CSS a livello di componente. Quella che potrebbe sembrare un'animazione abbastanza innocua a livello di componente potrebbe avere un impatto molto maggiore quando viene ripetuta in tutta la pagina ed è una delle tante parti mobili.

Nell'articolo di Tatiana, suggerisce di organizzare le animazioni (con prefers-reduced-motion ) in un unico file CSS, che può essere caricato solo se (prefers-reduced-motion: no-preference) risulta true. Vedere la somma totale di tutte le nostre animazioni potrebbe avere il vantaggio aggiuntivo di aiutarci a visualizzare l'esperienza di visitare il sito nel suo insieme e adattare di conseguenza i nostri stili a movimento ridotto.

Attivazione/disattivazione movimento esplicito

Sebbene prefers-reduced-motion sia utile, presenta lo svantaggio di soddisfare solo gli utenti che sono a conoscenza della funzionalità nelle impostazioni di sistema. Molti utenti non conoscono questa impostazione, mentre altri potrebbero utilizzare un computer preso in prestito, senza accedere alle impostazioni a livello di sistema. Tuttavia, altri potrebbero essere contenti del movimento per la stragrande maggioranza dei siti, ma trovano difficili da sopportare i siti con un uso intenso del movimento.

Può essere fastidioso dover modificare le preferenze di sistema solo per visitare un sito. Per questi motivi, in alcuni casi, potrebbe essere preferibile fornire un controllo esplicito sul sito stesso per attivare e disattivare il movimento . Possiamo implementarlo con JS.

La seguente demo ha diversi cerchi che si muovono sullo sfondo. Gli stili di animazione iniziali sono determinati dalle preferenze di sistema dell'utente (con prefers-reduced-motion ), tuttavia, l'utente ha la possibilità di attivare o disattivare il movimento tramite un pulsante. Questo aggiunge una classe al body , che possiamo usare per impostare gli stili in base alla preferenza selezionata. Come bonus, la scelta della preferenza di movimento viene conservata anche nella memoria locale, quindi viene "ricordata" alla visita successiva dell'utente.

Guarda la penna [Commutazione movimento ridotto](https://codepen.io/smashingmag/pen/porEQLB) di Michelle Barker.

Guarda l'interruttore a movimento ridotto della penna di Michelle Barker.

Proprietà personalizzate

Una caratteristica della demo è che l'interruttore imposta una proprietà personalizzata, --playState , che possiamo usare per riprodurre o mettere in pausa le animazioni. Questo potrebbe essere particolarmente utile se devi mettere in pausa o riprodurre più animazioni contemporaneamente. Prima di tutto, impostiamo lo stato di riproduzione in paused :

 .circle { animation-play-state: var(--playState, paused); }

Se l'utente ha impostato una preferenza per il movimento ridotto nelle impostazioni di sistema, possiamo impostare lo stato di riproduzione in running :

 @media (prefers-reduced-motion: no-preference) { body { --playState: running; } }

Nota: l'impostazione di questo sul body , al contrario del singolo elemento, significa che la proprietà personalizzata può essere ereditata.

Quando l'utente fa clic sull'interruttore, la proprietà personalizzata viene aggiornata sul body , che attiverà tutte le istanze in cui viene utilizzata:

 // This will pause all animations that use the `--playState` custom property document.body.style.setProperty('--playState', 'paused')

Questa potrebbe non essere la soluzione ideale in tutti i casi, ma un vantaggio è che l' animazione si interrompe semplicemente quando l'utente fa clic sull'interruttore, invece di tornare al suo stato iniziale, il che potrebbe essere piuttosto fastidioso.

Un ringraziamento speciale va a Scott O'Hara per i suoi consigli per migliorare l'accessibilità del toggle. Mi ha fatto sapere che alcuni screen reader non annunciano il testo del pulsante aggiornato, che viene modificato quando un utente fa clic sul pulsante, e ha suggerito invece role="switch" sul pulsante, con aria-checked on o off al clic.

Componente video

In alcuni casi, alternare il movimento a livello di componente potrebbe essere un'opzione migliore. Prendi una pagina web con uno sfondo video a riproduzione automatica. Dovremmo assicurarci che il video non venga riprodotto automaticamente per gli utenti che preferiscono il movimento ridotto, ma dovremmo comunque fornire loro un modo per riprodurre il video solo se lo desiderano . (Alcuni potrebbero obiettare che dovremmo evitare di riprodurre automaticamente i video, ma non sempre vinciamo quella battaglia!) Allo stesso modo, se un video è impostato per la riproduzione automatica per gli utenti senza una preferenza dichiarata, dovremmo anche fornire loro un modo per mettere in pausa il video.

Questa demo mostra come possiamo impostare l'attributo di riproduzione automatica quando l'utente non ha una preferenza di movimento dichiarata, implementando un pulsante di riproduzione/pausa personalizzato per consentire loro di attivare anche la riproduzione, indipendentemente dalle preferenze:

Guarda la penna [Video con preferenza di movimento](https://codepen.io/smashingmag/pen/qBXNjqR) di Michelle Barker.

Guarda il video della penna con la preferenza di movimento di Michelle Barker.

(Successivamente mi sono imbattuto in questo post di Scott O'Hara, che descriveva in dettaglio questo esatto caso d'uso.)

Utilizzo dell'elemento <picture>

Chris Coyier ha scritto un articolo interessante combinando un paio di tecniche per caricare diverse fonti multimediali a seconda delle preferenze di movimento dell'utente. Questo è piuttosto interessante, in quanto significa che per gli utenti che preferiscono il movimento ridotto , il file GIF molto più grande non verrà nemmeno scaricato. Lo svantaggio, per quanto posso vedere, è che una volta scaricato il file, non c'è modo per l'utente di tornare all'alternativa senza movimento.

Creo una versione modificata della demo che aggiunge questa opzione. (Attiva il reduced-motion nelle preferenze di sistema per vederlo in azione.) Sfortunatamente, quando passi tra le opzioni animate e senza movimento in Chrome, sembra che il file GIF venga scaricato di nuovo ogni volta, il che non è il caso in altri browser:

Guarda la penna [Preferisce la tecnica del movimento di riduzione PLUS! [forked]](https://codepen.io/smashingmag/pen/porbPXG) di Michelle Barker.

Vedere la tecnica del movimento di riduzione Preferisce la penna PLUS! [biforcato] di Michelle Barker.

Tuttavia, questa tecnica sembra un modo più rispettoso di visualizzare le GIF, che può essere fonte di frustrazione per gli utenti.

Supporto del browser e considerazioni finali

prefers-reduced-motion ha un eccellente supporto in tutti i browser moderni risalenti a un paio d'anni fa. Come abbiamo visto, adottando un approccio a movimento ridotto, i browser che non supportano riceveranno semplicemente un fallback reduced-motion . Non c'è motivo per non usarlo oggi per rendere i tuoi siti più accessibili.

Gli interruttori personalizzati hanno sicuramente un posto e possono migliorare notevolmente l'esperienza per gli utenti che non sono a conoscenza di questa impostazione o di cosa fa. Lo svantaggio per l'utente è l'incoerenza: se ogni sviluppatore è costretto a trovare la propria soluzione, l'utente deve cercare un interruttore di movimento in una posizione diversa su ogni sito web.

Sembra che il livello mancante qui siano i browser . Mi piacerebbe vedere i browser implementare le opzioni reduced-motion , da qualche parte facilmente accessibili all'utente, in modo che le persone sappiano dove trovarlo indipendentemente dal sito che stanno navigando. Potrebbe anche incoraggiare gli sviluppatori a dedicare più tempo a garantire l'accessibilità del movimento.

Risorse correlate

  • Specifica di media query di livello 5, World Wide Web Consortium (W3C)
  • prefers-reduced-motion , MDN Web Docs, Mozilla
  • Design con movimento ridotto per sensibilità al movimento, Val Head, Smashing Magazine
  • Adottare un primo approccio senza movimento alle animazioni, Tatiana Mac
  • Tecnica cinematografica ridotta, Take 2, Chris Coyier, CSS-Tricks
  • La rivisitazione prefers-reduced-motion , The Reduced Motion Media Query, Eric Bailey, CSS-Tricks
  • Ridurre il movimento per migliorare l'accessibilità, Lindsey Kopacz