Respetar las preferencias de movimiento de los usuarios
Publicado: 2022-03-10prefers-reduced-motion
tiene un soporte excelente en todos los navegadores modernos desde hace un par de años. En este artículo, Michelle Barker explica por qué no hay razón para no usarlo hoy para hacer que sus sitios sean más accesibles.Cuando se trabaja con movimiento en la web, es importante tener en cuenta que no todos lo experimentan de la misma manera. Lo que puede sentirse suave y resbaladizo para algunos puede ser molesto o distraer a otros, o peor aún, inducir sentimientos de enfermedad o incluso causar convulsiones. Los sitios web con mucho movimiento también pueden tener un mayor impacto en la duración de la batería de los dispositivos móviles o hacer que se utilicen más datos (la reproducción automática de videos, por ejemplo, requerirá más datos del usuario que una imagen estática). Estas son solo algunas de las razones por las que los sitios con mucho movimiento pueden no ser deseables para todos.
La mayoría de los nuevos sistemas operativos permiten al usuario establecer sus preferencias de movimiento en la configuración a nivel del sistema. La consulta de medios prefers-reduced-motion
preferido (parte de la especificación de Consultas de medios de nivel 5) nos permite detectar las preferencias de movimiento a nivel del sistema de los usuarios y aplicar estilos CSS que respeten eso.
Las dos opciones para prefers-reduced-motion
son reduce
o no-preference
. Podemos usarlo de la siguiente manera en nuestro CSS para desactivar la animación de un elemento si el usuario ha establecido explícitamente una preferencia por el movimiento reducido :
.some-element { animation: bounce 1200ms; } @media (prefers-reduced-motion: reduce) { .some-element { animation: none; } }
Por el contrario, podríamos configurar la animación solo si el usuario no tiene preferencia de movimiento. Esto tiene la ventaja de reducir la cantidad de código que necesitamos escribir y significa que es menos probable que nos olvidemos de atender las preferencias de movimiento de los usuarios:
@media (prefers-reduced-motion: no-preference) { .some-element { animation: bounce 1200ms; } }
Una ventaja adicional es que los navegadores más antiguos que no son compatibles prefers-reduced-motion
ignorarán la regla y solo mostrarán nuestro elemento original sin movimiento.
¿Qué regla?
A diferencia de las consultas de medios de ancho min-width
max-width
, donde el consenso más o menos establecido es móvil primero (por lo tanto, favorece min-width
), no existe una forma "correcta" única de escribir sus estilos de movimiento reducido. Tiendo a favorecer el segundo ejemplo (aplicar animaciones solo si prefers-reduced-motion: no-preference
evalúa como verdadero), por las razones enumeradas anteriormente. Tatiana Mac escribió este excelente artículo que cubre algunos de los enfoques que los desarrolladores podrían considerar, así como muchos otros puntos importantes, incluidas las preguntas clave que se deben hacer al diseñar con movimiento en la web.
Como siempre, la comunicación del equipo y una estrategia consistente son clave para garantizar que se cubran todas las bases en lo que respecta a la accesibilidad web.
Uso práctico: aplicar prefers-reduced-motion
al comportamiento de desplazamiento
prefers-reduced-motion
tiene muchas aplicaciones más allá de aplicar (o no aplicar) animaciones o transiciones de fotogramas clave. Un ejemplo es el desplazamiento suave. Si configuramos scroll-behaviour: smooth
en nuestro elemento html
, cuando un usuario haga clic en un enlace de anclaje en la página, se desplazará suavemente a la posición adecuada en la página ( actualmente no es compatible con Safari ):
html { scroll-behavior: smooth; }
Desafortunadamente, en CSS no tenemos mucho control sobre ese comportamiento en este momento. Si tenemos una página larga de contenido, la página se desplaza muy rápido, lo que puede ser una experiencia bastante desagradable para alguien con sensibilidad al movimiento. Al envolverlo en una consulta de medios, podemos evitar que ese comportamiento se aplique en los casos en que el usuario tiene una preferencia reduced-motion
:
@media (prefers-reduced-motion: no-preference) { html { scroll-behavior: smooth; } }
Catering para preferencias de movimiento en Javascript
A veces necesitamos aplicar movimiento en JavaScript en lugar de CSS. De manera similar, podemos detectar las preferencias de movimiento de un usuario con JS, usando matchMedia
. Veamos cómo podemos implementar condicionalmente un comportamiento de desplazamiento suave en nuestro código 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 }) })
El mismo principio se puede usar para detectar si se deben implementar interfaces de usuario ricas en movimiento con bibliotecas JS, o incluso si se deben cargar las bibliotecas.
En el siguiente fragmento de código, la función regresa antes si el usuario prefiere un movimiento reducido, lo que evita la importación innecesaria de una gran dependencia: una ganancia de rendimiento para el usuario. Si no tienen un conjunto de preferencias de movimiento, entonces podemos importar dinámicamente la biblioteca de animación de Greensock e inicializar nuestras animaciones.
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
no significa sin movimiento
Al aplicar estilo a las preferencias de movimiento reducido, es importante que sigamos proporcionando al usuario indicadores significativos y accesibles de cuándo se ha producido una acción. Por ejemplo, al desactivar un estado de desplazamiento que distrae o que requiere mucho movimiento para los usuarios que prefieren un movimiento reducido, debemos tener cuidado de proporcionar un estilo alternativo claro para cuando el usuario se desplaza sobre el elemento.
La siguiente demostración muestra una transición elaborada cuando el usuario se desplaza o se enfoca en un elemento de la galería si no tiene definida una preferencia de movimiento. Si prefieren un movimiento reducido, la transición es más sutil, pero todavía indica claramente el estado de suspensión:
El movimiento reducido tampoco significa necesariamente eliminar todas las transformaciones de nuestra página web. Por ejemplo, es poco probable que un botón que tiene un ícono de flecha pequeña que se mueve unos pocos píxeles al pasar el mouse cause problemas a alguien que prefiere una experiencia de movimiento reducido y proporciona un indicador más útil de un cambio de estado que el color solo.
A veces veo desarrolladores que aplican estilos de movimiento reducido de la siguiente manera, lo que elimina todas las transiciones y animaciones en todos los elementos:
@media screen and (prefers-reduced-motion: reduce) { * { animation: none !important; transition: none !important; scroll-behavior: auto !important; } }
Podría decirse que esto es mejor que ignorar las preferencias de movimiento de los usuarios, pero no nos permite adaptar fácilmente los elementos para proporcionar transiciones más sutiles cuando sea necesario.
En el siguiente fragmento de código, tenemos un botón que crece en escala al pasar el mouse por encima . Estamos cambiando los colores y la escala, pero los usuarios con preferencia por el movimiento reducido no obtendrán ninguna transición:
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); } }
Echa un vistazo a esta demostración para ver el efecto. Quizás esto no sea lo ideal, ya que el cambio repentino de color sin una transición podría resultar más molesto que una transición de un par de cientos de milisegundos. Esta es una de las razones por las que, en general, generalmente prefiero diseñar para movimiento reducido caso por caso.
Si está interesado, esta es la misma demostración refactorizada para permitir personalizar la transición cuando sea necesario. Utiliza una propiedad personalizada para la duración de la transición, lo que nos permite activar y desactivar la transición de escala sin tener que volver a escribir toda la declaración.
Cuándo es mejor eliminar la animación
Eric Bailey plantea el punto de que "no todos los dispositivos que pueden acceder a la web también pueden generar animaciones, o generar animaciones sin problemas" en su artículo, "Revisando las preferencias de movimiento reducido, la consulta de medios de movimiento reducido". Para dispositivos con una frecuencia de actualización baja, que puede causar animaciones irregulares, de hecho, podría ser preferible eliminar la animación . La función de update
de medios se puede utilizar para determinar esto:
@media screen and (prefers-reduced-motion: reduce), (update: slow) { * { animation-duration: 0.001ms !important; animation-iteration-count: 1 !important; transition-duration: 0.001ms !important; } }
Asegúrese de leer el artículo completo para conocer las recomendaciones de Eric, ya que es una persona de primer nivel a seguir en el campo de la accesibilidad.
La suma de todas las partes
Es importante tener en cuenta el diseño general de la página cuando se centra tanto en el CSS a nivel de componente. Lo que podría parecer una animación bastante inocua a nivel de componente podría tener un impacto mucho mayor cuando se repite a lo largo de la página y es una de las muchas partes móviles.
En el artículo de Tatiana, ella sugiere organizar las animaciones (con prefers-reduced-motion
) en un solo archivo CSS, que se puede cargar solo si (prefers-reduced-motion: no-preference)
evalúa como verdadero. Ver la suma total de todas nuestras animaciones podría tener el beneficio adicional de ayudarnos a visualizar la experiencia de visitar el sitio como un todo y adaptar nuestros estilos de movimiento reducido en consecuencia.
Cambio de movimiento explícito
Si bien prefers-reduced-motion
es útil, tiene el inconveniente de que solo atiende a los usuarios que conocen la función en la configuración de su sistema. Muchos usuarios desconocen esta configuración, mientras que otros pueden estar usando una computadora prestada, sin acceso a la configuración a nivel del sistema. Aún así, otros pueden estar contentos con el movimiento para la gran mayoría de los sitios, pero encuentran que los sitios con un uso intensivo del movimiento son difíciles de soportar.
Puede ser molesto tener que ajustar las preferencias de su sistema solo para visitar un sitio. Por estas razones, en algunos casos, podría ser preferible proporcionar un control explícito en el sitio mismo para activar y desactivar el movimiento . Podemos implementar esto con JS.
La siguiente demostración tiene varios círculos a la deriva alrededor del fondo. Los estilos de animación iniciales están determinados por las preferencias del sistema del usuario (con prefers-reduced-motion
), sin embargo, el usuario tiene la capacidad de activar o desactivar el movimiento a través de un botón. Esto agrega una clase al body
, que podemos usar para establecer estilos según la preferencia seleccionada. Como beneficio adicional, la elección de la preferencia de movimiento también se conserva en el almacenamiento local, por lo que se "recuerda" cuando el usuario visita la próxima vez.
Propiedades personalizadas
Una característica de la demostración es que el conmutador establece una propiedad personalizada, --playState
, que podemos usar para reproducir o pausar animaciones. Esto podría ser especialmente útil si necesita pausar o reproducir varias animaciones a la vez. En primer lugar, establecemos el estado de reproducción en paused
:
.circle { animation-play-state: var(--playState, paused); }
Si el usuario ha establecido una preferencia por el movimiento reducido en la configuración de su sistema, podemos establecer el estado de reproducción en running
:
@media (prefers-reduced-motion: no-preference) { body { --playState: running; } }
Nota: Establecer esto en el body
, a diferencia del elemento individual, significa que la propiedad personalizada se puede heredar.
Cuando el usuario hace clic en el interruptor, la propiedad personalizada se actualiza en el body
, que alternará cualquier instancia en la que se use:
// This will pause all animations that use the `--playState` custom property document.body.style.setProperty('--playState', 'paused')
Puede que esta no sea la solución ideal en todos los casos, pero una ventaja es que la animación simplemente se detiene cuando el usuario hace clic en el interruptor, en lugar de volver a su estado inicial, lo que podría ser bastante molesto.
Agradecimiento especial a Scott O'Hara por sus recomendaciones para mejorar la accesibilidad de la palanca. Me hizo saber que algunos lectores de pantalla no anuncian el texto del botón actualizado, que cambia cuando un usuario hace clic en el botón, y sugirió role="switch"
en el botón en su lugar, con aria-checked
on
o off
al hacer clic.
Componente de vídeo
En algunos casos, alternar el movimiento en el nivel del componente podría ser una mejor opción. Tome una página web con un fondo de video de reproducción automática. Debemos asegurarnos de que el video no se reproduzca automáticamente para los usuarios que prefieren el movimiento reducido, pero aun así debemos proporcionarles una forma de reproducir el video solo si así lo desean . (Algunos podrían argumentar que deberíamos evitar la reproducción automática de videos, ¡pero no siempre ganamos esa batalla!) Del mismo modo, si un video está configurado para reproducirse automáticamente para los usuarios sin una preferencia establecida, también debemos proporcionarles una forma de pausar el vídeo.
Esta demostración muestra cómo podemos configurar el atributo de reproducción automática cuando el usuario no tiene una preferencia de movimiento establecida, implementando un botón personalizado de reproducción/pausa para permitirles alternar también la reproducción, independientemente de su preferencia:
(Posteriormente encontré esta publicación de Scott O'Hara, que detalla este caso de uso exacto).
Uso del elemento <picture>
Chris Coyier escribió un artículo interesante que combina un par de técnicas para cargar diferentes fuentes de medios según las preferencias de movimiento del usuario. Esto es genial, ya que significa que para los usuarios que prefieren el movimiento reducido , el archivo GIF mucho más grande ni siquiera se descargará. La desventaja, por lo que puedo ver, es que una vez que se descarga el archivo, no hay forma de que el usuario vuelva a cambiar a la alternativa sin movimiento.
Creo una versión modificada de la demostración que agrega esta opción. (Active el reduced-motion
en las preferencias de su sistema para verlo en acción). Desafortunadamente, al alternar entre las opciones animadas y sin movimiento en Chrome, parece que el archivo GIF se descarga de nuevo cada vez, lo cual no es el caso en Chrome. otros navegadores:
Aún así, esta técnica parece una forma más respetuosa de mostrar GIF, lo que puede ser una fuente de frustración para los usuarios.
Soporte del navegador y pensamientos finales
prefers-reduced-motion
tiene un excelente soporte en todos los navegadores modernos desde hace un par de años. Como hemos visto, al adoptar un enfoque de movimiento reducido primero, los navegadores no compatibles simplemente obtendrán un respaldo reduced-motion
. No hay razón para no usarlo hoy para hacer que sus sitios sean más accesibles.
Los conmutadores personalizados definitivamente tienen un lugar y pueden mejorar enormemente la experiencia para los usuarios que no conocen esta configuración o lo que hace. La desventaja para el usuario es la inconsistencia: si cada desarrollador se ve obligado a encontrar su propia solución, el usuario debe buscar un interruptor de movimiento en un lugar diferente en cada sitio web.
Parece que la capa que falta aquí son los navegadores . Me encantaría ver que los navegadores implementen reduced-motion
, en algún lugar de fácil acceso para el usuario, para que las personas sepan dónde encontrarlo independientemente del sitio que estén navegando. También podría alentar a los desarrolladores a dedicar más tiempo a garantizar la accesibilidad del movimiento.
Recursos Relacionados
- Especificación de consultas de medios de nivel 5, World Wide Web Consortium (W3C)
-
prefers-reduced-motion
, MDN Web Docs, Mozilla - Diseño con movimiento reducido para sensibilidades de movimiento, Val Head, Smashing Magazine
- Adoptando un enfoque sin movimiento para las animaciones, Tatiana Mac
- Técnica de imagen en movimiento reducida, toma 2, Chris Coyier, CSS-Tricks
- Revisitando
prefers-reduced-motion
, The Reduced Motion Media Query, Eric Bailey, CSS-Tricks - Reducción del movimiento para mejorar la accesibilidad, Lindsey Kopacz