Respectarea preferințelor de mișcare ale utilizatorilor
Publicat: 2022-03-10prefers-reduced-motion
are un suport excelent în toate browserele moderne, cu câțiva ani în urmă. În acest articol, Michelle Barker explică de ce nu există niciun motiv să nu îl folosiți astăzi pentru a vă face site-urile mai accesibile.Când lucrați cu mișcarea pe web, este important să luați în considerare faptul că nu toată lumea o experimentează în același mod. Ceea ce s-ar putea simți neted și neted pentru unii ar putea fi enervant sau distrage atenția pentru alții - sau, mai rău, poate provoca senzații de rău sau chiar provoca convulsii. Site-urile web cu multă mișcare pot avea, de asemenea, un impact mai mare asupra duratei de viață a bateriei dispozitivelor mobile sau pot determina utilizarea mai multor date (de exemplu, redarea automată a videoclipurilor va necesita mai multe date ale utilizatorului decât o imagine statică). Acestea sunt doar câteva dintre motivele pentru care site-urile cu mișcare grele ar putea să nu fie de dorit pentru toți.
Majoritatea sistemelor de operare noi permit utilizatorului să își stabilească preferințele de mișcare în setările la nivel de sistem. Interogarea media prefers-reduced-motion
(parte a specificației Level 5 Media Queries) ne permite să detectăm preferințele de mișcare la nivel de sistem ale utilizatorilor și să aplicăm stiluri CSS care le respectă.
Cele două opțiuni pentru prefers-reduced-motion
sunt reduce
sau no-preference
. Îl putem folosi în următorul mod în CSS-ul nostru pentru a dezactiva animația unui element dacă utilizatorul a setat în mod explicit o preferință pentru mișcare redusă :
.some-element { animation: bounce 1200ms; } @media (prefers-reduced-motion: reduce) { .some-element { animation: none; } }
În schimb, am putea seta animația doar dacă utilizatorul nu are preferințe de mișcare. Acest lucru are avantajul de a reduce cantitatea de cod pe care trebuie să o scriem și înseamnă că este mai puțin probabil să uităm să satisfacem preferințele de mișcare ale utilizatorilor:
@media (prefers-reduced-motion: no-preference) { .some-element { animation: bounce 1200ms; } }
Un avantaj suplimentar este că browserele mai vechi care nu acceptă prefers-reduced-motion
vor ignora regula și vor afișa doar elementul nostru original, fără mișcare.
Care regulă?
Spre deosebire de interogările media cu lățimea min-width
max-width
, în care consensul mai mult sau mai puțin stabilit este mai întâi pe mobil (prin urmare, favorizând min-width
), nu există o singură modalitate „corectă” de a vă scrie stilurile cu mișcare redusă. Tind să prefer al doilea exemplu (aplicarea de animații numai dacă prefers-reduced-motion: no-preference
evaluează adevărat), din motivele enumerate mai sus. Tatiana Mac a scris acest articol excelent, care acoperă unele dintre abordările pe care dezvoltatorii le-ar putea lua în considerare, precum și o mulțime de alte puncte grozave, inclusiv întrebări cheie de adresat atunci când proiectează cu mișcare pe web.
Ca întotdeauna, comunicarea în echipă și o strategie coerentă sunt cheia pentru a ne asigura că toate bazele sunt acoperite atunci când vine vorba de accesibilitatea web.
Utilizare practică: aplicarea prefers-reduced-motion
pentru a derula comportamentul
prefers-reduced-motion
are o mulțime de aplicații dincolo de aplicarea (sau neaplicarea) animațiilor sau tranzițiilor de cadre cheie. Un exemplu este defilarea lină. Dacă setăm scroll-behaviour: smooth
pe elementul nostru html
, atunci când un utilizator face clic pe un link de ancorare în pagină, acesta va fi derulat fără probleme la poziția corespunzătoare pe pagină ( în prezent nu este acceptat în Safari ):
html { scroll-behavior: smooth; }
Din păcate, în CSS nu avem prea mult control asupra acestui comportament în acest moment. Dacă avem o pagină lungă de conținut, pagina se derulează foarte repede, ceea ce poate fi o experiență destul de neplăcută pentru cineva cu sensibilitate la mișcare. Prin includerea acesteia într-o interogare media, putem preveni aplicarea acestui comportament în cazurile în care utilizatorul are o preferință reduced-motion
:
@media (prefers-reduced-motion: no-preference) { html { scroll-behavior: smooth; } }
Catering pentru preferințele de mișcare în Javascript
Uneori trebuie să aplicăm mișcare în JavaScript, mai degrabă decât în CSS. În mod similar, putem detecta preferințele de mișcare ale unui utilizator cu JS, folosind matchMedia
. Să vedem cum putem implementa în mod condiționat comportamentul de defilare uniform în codul nostru 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 }) })
Același principiu poate fi folosit pentru a detecta dacă să implementați interfețe de utilizare bogate în mișcare cu biblioteci JS - sau chiar dacă să încărcați bibliotecile în sine.
În următorul fragment de cod, funcția revine devreme dacă utilizatorul preferă mișcarea redusă, evitând importul inutil al unei dependențe mari - un câștig de performanță pentru utilizator. Dacă nu au setate preferințe de mișcare, atunci putem importa în mod dinamic biblioteca de animații Greensock și inițializa animațiile noastre.
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
nu înseamnă că nu există mișcare
Atunci când modelați pentru preferințe de mișcare redusă, este important să oferim în continuare utilizatorului indicatori semnificativi și accesibili despre momentul în care a avut loc o acțiune. De exemplu, atunci când dezactivăm o stare de hover care distrag atenția sau care necesită mișcare intensivă pentru utilizatorii care preferă mișcare redusă, trebuie să avem grijă să oferim un stil alternativ clar pentru atunci când utilizatorul plutește pe element.
Următoarea demonstrație arată o tranziție elaborată atunci când utilizatorul trece cu mouse-ul sau se concentrează pe un articol din galerie dacă nu are setate preferințe de mișcare. Dacă preferă mișcarea redusă, tranziția este mai subtilă, dar totuși indică clar starea de hover:
Mișcarea redusă nu înseamnă neapărat eliminarea tuturor transformărilor de pe pagina noastră web. De exemplu, un buton care are o pictogramă săgeată mică care mișcă câțiva pixeli la trecerea cursorului este puțin probabil să cauzeze probleme pentru cineva care preferă o experiență de mișcare redusă și oferă un indicator mai util al unei schimbări de stare decât doar culoarea.
Uneori văd dezvoltatori care aplică stiluri de mișcare redusă în felul următor, ceea ce elimină toate tranzițiile și animațiile pe toate elementele:
@media screen and (prefers-reduced-motion: reduce) { * { animation: none !important; transition: none !important; scroll-behavior: auto !important; } }
Acest lucru este probabil mai bun decât ignorarea preferințelor de mișcare ale utilizatorilor, dar nu ne permite să personalizăm cu ușurință elementele pentru a oferi tranziții mai subtile atunci când este necesar.
În următorul fragment de cod, avem un buton care crește la scară la trecerea cursorului . Facem tranziția la culori și la scară, dar utilizatorii care preferă mișcarea redusă nu vor avea nicio tranziție:
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); } }
Consultați această demonstrație pentru a vedea efectul. Poate că acest lucru nu este ideal, deoarece schimbarea bruscă a culorii fără o tranziție ar putea fi mai tulburătoare decât o tranziție de câteva sute de milisecunde. Acesta este unul dintre motivele pentru care, în general, prefer să modelez pentru mișcare redusă de la caz la caz.
Dacă sunteți interesat, acesta este același demo refactorizat pentru a permite personalizarea tranziției atunci când este necesar. Folosește o proprietate personalizată pentru durata tranziției, care ne permite să activăm și să dezactivăm tranziția la scară fără a fi nevoie să rescriem întreaga declarație.
Când eliminarea animației este mai bună
Eric Bailey subliniază faptul că „nu orice dispozitiv care poate accesa web-ul poate, de asemenea, reda animația sau reda animația fără probleme“ în articolul său, „Revisiting prefers-reduced-motion, the reduced motion media query”. Pentru dispozitivele cu o rată de reîmprospătare scăzută, care poate provoca animații neplăcute, ar putea fi de fapt de preferat să eliminați animația . Funcția de update
media poate fi utilizată pentru a determina acest lucru:
@media screen and (prefers-reduced-motion: reduce), (update: slow) { * { animation-duration: 0.001ms !important; animation-iteration-count: 1 !important; transition-duration: 0.001ms !important; } }
Asigurați-vă că citiți articolul complet pentru recomandările lui Eric, deoarece este o persoană de prim rang de urmat în domeniul accesibilității.
Suma tuturor părților
Este important să țineți cont de designul general al paginii atunci când vă concentrați atât de mult pe CSS la nivel de componentă. Ceea ce ar putea părea o animație destul de inofensivă la nivel de componentă ar putea avea un impact mult mai mare atunci când se repetă pe toată pagina și este una dintre multele părți mobile.
În articolul Tatianei, ea sugerează organizarea animațiilor (cu prefers-reduced-motion
) într-un singur fișier CSS, care poate fi încărcat numai dacă (prefers-reduced-motion: no-preference)
evaluează adevărat. Vederea sumei tuturor animațiilor noastre ar putea avea avantajul suplimentar de a ne ajuta să vizualizăm experiența de a vizita site-ul ca întreg și să ne adaptăm stilurile cu mișcare redusă în consecință.
Comutare explicită de mișcare
În timp ce prefers-reduced-motion
este utilă, are dezavantajul de a răspunde doar utilizatorilor care sunt conștienți de caracteristica din setările lor de sistem. Mulți utilizatori nu cunosc această setare, în timp ce alții ar putea folosi un computer împrumutat, fără acces la setările la nivel de sistem. Cu toate acestea, alții ar putea fi mulțumiți de mișcare pentru marea majoritate a site-urilor, dar găsesc site-uri cu o utilizare intensă a mișcării greu de suportat.
Poate fi enervant să fii nevoit să-ți ajustezi preferințele de sistem doar pentru a vizita un site. Din aceste motive, în unele cazuri, ar putea fi de preferat să se ofere un control explicit pe site-ul însuși pentru a activa și dezactiva mișcarea . Putem implementa acest lucru cu JS.
Următoarea demonstrație are mai multe cercuri plutind pe fundal. Stilurile inițiale de animație sunt determinate de preferințele de sistem ale utilizatorului (cu prefers-reduced-motion
), cu toate acestea, utilizatorul are capacitatea de a activa sau dezactiva mișcarea printr-un buton. Acest lucru adaugă o clasă la body
, pe care o putem folosi pentru a seta stiluri în funcție de preferința selectată. Ca bonus, alegerea preferinței de mișcare este păstrată și în stocarea locală – astfel încât este „rememorată” la următoarea vizită de utilizator.
Proprietăți personalizate
O caracteristică a demonstrației este că comutatorul setează o proprietate personalizată, --playState
, pe care o putem folosi pentru a reda sau întrerupe animațiile. Acest lucru ar putea fi deosebit de util dacă trebuie să întrerupeți sau să redați mai multe animații simultan. În primul rând, am setat starea de redare la paused
:
.circle { animation-play-state: var(--playState, paused); }
Dacă utilizatorul a setat o preferință pentru mișcare redusă în setările sistemului său, putem seta starea de redare la running
:
@media (prefers-reduced-motion: no-preference) { body { --playState: running; } }
Notă: setarea acestui lucru pe body
, spre deosebire de elementul individual, înseamnă că proprietatea personalizată poate fi moștenită.
Când utilizatorul dă clic pe comutator, proprietatea personalizată este actualizată pe body
, care va comuta în orice situație în care este utilizată:
// This will pause all animations that use the `--playState` custom property document.body.style.setProperty('--playState', 'paused')
Aceasta ar putea să nu fie soluția ideală în toate cazurile, dar un avantaj este că animația pur și simplu se întrerupe atunci când utilizatorul face clic pe comutator, mai degrabă decât să sară înapoi la starea sa inițială, ceea ce ar putea fi destul de șocant.
Mulțumiri speciale lui Scott O'Hara pentru recomandările sale pentru îmbunătățirea accesibilității comutatorului. M-a făcut conștient de faptul că unii cititori de ecran nu anunță textul actualizat al butonului, care este schimbat atunci când un utilizator dă clic pe buton, și a sugerat role="switch"
pe buton, cu aria-checked
comutat la on
sau off
la clic.
Componenta video
În unele cazuri, comutarea mișcării la nivel de componentă ar putea fi o opțiune mai bună. Luați o pagină web cu un fundal video cu redare automată. Ar trebui să ne asigurăm că videoclipul nu se redă automat pentru utilizatorii care preferă mișcarea redusă, dar ar trebui să le oferim totuși o modalitate de a reda videoclipul numai dacă aleg . (Unii ar putea argumenta că ar trebui să evităm redarea automată a videoclipurilor, dar nu întotdeauna câștigăm această bătălie!) De asemenea, dacă un videoclip este setat să fie redat automat pentru utilizatorii fără o preferință declarată, ar trebui să le oferim și o modalitate de a întrerupeți videoclipul.
Această demonstrație arată cum putem seta atributul de redare automată atunci când utilizatorul nu are nicio preferință de mișcare declarată, implementând un buton personalizat de redare/pauză pentru a le permite să comute și redarea, indiferent de preferință:
(Ulterior, am găsit această postare a lui Scott O'Hara, care detaliază exact acest caz de utilizare.)
Folosind elementul <picture>
Chris Coyier a scris un articol interesant care combină câteva tehnici pentru a încărca diferite surse media în funcție de preferințele de mișcare ale utilizatorului. Acest lucru este destul de grozav, deoarece înseamnă că pentru utilizatorii care preferă mișcarea redusă , fișierul GIF mult mai mare nici măcar nu va fi descărcat. Dezavantajul, din câte văd, este că odată ce fișierul este descărcat, utilizatorul nu are nicio modalitate de a reveni la alternativa fără mișcare.
Creez o versiune modificată a demo-ului care adaugă această opțiune. (Activați reduced-motion
în preferințele dvs. de sistem pentru a-l vedea în acțiune.) Din păcate, când comutați între opțiunile animate și fără mișcare în Chrome, se pare că fișierul GIF este descărcat din nou de fiecare dată, ceea ce nu este cazul în alte browsere:
Totuși, această tehnică pare o modalitate mai respectuoasă de a afișa GIF-uri, care poate fi o sursă de frustrare pentru utilizatori.
Suport pentru browser și gânduri finale
prefers-reduced-motion
are un suport excelent în toate browserele moderne, cu câțiva ani în urmă. După cum am văzut, adoptând o abordare mai întâi cu mișcare redusă, browserele care nu acceptă vor primi pur și simplu o reduced-motion
. Nu există niciun motiv să nu îl folosiți astăzi pentru a vă face site-urile mai accesibile.
Comutatoarele personalizate au cu siguranță un loc și pot îmbunătăți considerabil experiența pentru utilizatorii care nu cunosc această setare sau ce face aceasta. Dezavantajul utilizatorului este inconsecvența - dacă fiecare dezvoltator este forțat să vină cu propria soluție, utilizatorul trebuie să caute o comutare de mișcare într-un loc diferit pe fiecare site web.
Se pare că stratul care lipsește aici este browserele . Mi-ar plăcea să văd că browserele implementează reduced-motion
, undeva ușor accesibile utilizatorului, astfel încât oamenii să știe unde să le găsească, indiferent de site-ul pe care îl navighează. S-ar putea să încurajeze dezvoltatorii să petreacă mai mult timp asigurând, de asemenea, accesibilitatea la mișcare.
Resurse conexe
- Specificații de interogări media de nivel 5, World Wide Web Consortium (W3C)
-
prefers-reduced-motion
, MDN Web Docs, Mozilla - Design cu mișcare redusă pentru sensibilități la mișcare, Val Head, Smashing Magazine
- Abordarea animațiilor fără mișcare, Tatiana Mac
- Tehnica de filmare redusă, Take 2, Chris Coyier, CSS-Tricks
- Revizuirea
prefers-reduced-motion
, The Reduced Motion Media Query, Eric Bailey, CSS-Tricks - Reducerea mișcării pentru îmbunătățirea accesibilității, Lindsey Kopacz