prefers-reduced-motion: A veces, menos movimiento es más

La consulta de medios con preferencia de movimiento reducido detecta si el usuario solicitó al sistema operativo que minimice la cantidad de animación o movimiento que usa.

No a todos les gustan las animaciones o transiciones decorativas, y algunos usuarios experimentan mareos cuando se enfrentan al desplazamiento con paralaje, los efectos de zoom, etcétera. La consulta de medios prefers-reduced-motion de preferencias del usuario te permite diseñar una variante con movimiento reducido de tu sitio para los usuarios que expresaron esta preferencia.

Navegadores compatibles

  • 74
  • 79
  • 63
  • 10.1

Origen

Demasiado movimiento en la vida real y en la Web

El otro día, patinaba sobre hielo con mis hijos. Fue un día encantador, el sol brillaba y la pista de hielo estaba abarrotada de personas ⛸. El único problema es que no llevo bien con las multitudes. Con tantos objetivos en movimiento, no puedo concentrarme en nada y termino perdido con una sensación de sobrecarga visual completa, casi como mirar un hormiguero 🐜.

Grupo de pies de personas patinando sobre hielo.
Sobrecarga visual en la vida real.

En ocasiones, puede suceder lo mismo en la Web: con anuncios intermitentes, efectos de paralaje elegantes, animaciones de revelación sorprendentes, videos con reproducción automática, etc., la Web a veces puede ser bastante abrumadora. Afortunadamente, a diferencia de lo que ocurre en la vida real, existe la solución para eso. La consulta de medios de CSS prefers-reduced-motion permite a los desarrolladores crear una variante de una página para los usuarios que prefieren el movimiento reducido. Esto puede incluir desde abstenerse de tener videos de reproducción automática hasta inhabilitar ciertos efectos meramente decorativos o rediseñar una página por completo para ciertos usuarios.

Antes de profundizar en la función, demos un paso atrás y pensemos para qué se usan las animaciones en la Web. Si lo deseas, también puedes omitir la información de referencia y pasar directamente a los detalles técnicos a continuación.

Animación en la Web

A menudo, la animación se usa para proporcionar comentarios al usuario, por ejemplo, para informarle que se recibió y procesó una acción. Por ejemplo, en un sitio web de compras, se podría animar un producto para "volar" a un carrito de compras virtual, representado como un ícono en la esquina superior derecha del sitio.

Otro caso de uso implica usar el movimiento para hackear la percepción del usuario con una combinación de pantallas de esqueleto, metadatos contextuales y vistas previas de imágenes de baja calidad para ocupar mucho tiempo del usuario y hacer que toda la experiencia se sienta más rápida. La idea es brindarle al usuario contexto sobre lo que viene y, mientras tanto, cargar los elementos lo más rápido posible.

Por último, existen efectos decorativos, como gradientes animados, desplazamiento con paralaje, videos de fondo y muchos más. Si bien muchos usuarios disfrutan de esas animaciones, a algunos no les gustan porque se sienten distraídos o ralentizados por ellas. En el peor de los casos, los usuarios podrían sufrir mareos como si fuera una experiencia de la vida real, por lo que reducir las animaciones es una necesidad médica.

Trastorno del espectro vestibular activado por el movimiento

Algunos usuarios experimentan distracciones o náuseas por el contenido animado. Por ejemplo, las animaciones de desplazamiento pueden causar trastornos vestibulares cuando los elementos que no son el principal asociado con el desplazamiento se mueven mucho. Por ejemplo, las animaciones de desplazamiento con paralaje pueden causar trastornos vestibulares, ya que los elementos en segundo plano se mueven a una velocidad diferente a la de los elementos en primer plano. Las reacciones ante trastornos vestibulares (del oído interno) incluyen mareos, náuseas y migrañas. A veces, es necesario descansar en cama para recuperarse.

Cómo quitar movimiento en sistemas operativos

Muchos sistemas operativos han tenido una configuración de accesibilidad para especificar una preferencia por un movimiento reducido durante mucho tiempo. En las siguientes capturas de pantalla, se muestran la preferencia Reduce motion de macOS Mojave y la preferencia Quitar animaciones de Android Pie. Cuando se marcan estas preferencias, estas preferencias hacen que el sistema operativo no use efectos decorativos, como animaciones de inicio de apps. Las propias aplicaciones pueden y deben respetar esta configuración también y quitar todas las animaciones innecesarias.

Captura de la pantalla de configuración de macOS con la casilla de verificación “Reducir movimiento” marcada.
Captura de la pantalla de configuración de Android con la casilla de verificación "Quitar animaciones" marcada.

Cómo quitar movimiento en la Web

El nivel de consultas de medios 5 lleva la preferencia del usuario de movimiento reducido también a la Web. Las consultas de medios permiten a los autores probar y consultar valores o funciones del usuario-agente o del dispositivo de visualización, independientemente del documento que se renderiza. La consulta de medios prefers-reduced-motion se usa para detectar si el usuario estableció una preferencia de sistema operativo para minimizar la cantidad de animación o movimiento que usa. Puede tener dos valores posibles:

  • no-preference: Indica que el usuario no hizo ninguna preferencia en el sistema operativo subyacente. El valor de esta palabra clave se evalúa como false en el contexto booleano.
  • reduce: Indica que el usuario estableció una preferencia de sistema operativo que indica que las interfaces deben minimizar el movimiento o la animación, preferentemente hasta el punto en el que se quitan todos los movimientos no esenciales.

Trabaja con la consulta de medios desde contextos de CSS y JavaScript

Al igual que con todas las consultas de medios, prefers-reduced-motion se puede verificar desde un contexto de CSS y desde un contexto de JavaScript.

A modo de ejemplo, supongamos que tengo un botón de registro importante en el que quiero que el usuario haga clic. Podría definir una animación de "vibración" que llame la atención, pero como buen usuario de la Web solo la reproduciré para los usuarios que aceptan explícitamente las animaciones, pero no para todos los demás, que pueden ser usuarios que inhabilitaron las animaciones o usuarios de navegadores que no comprenden la consulta de medios.

/*
  If the user has expressed their preference for
  reduced motion, then don't use animations on buttons.
*/
@media (prefers-reduced-motion: reduce) {
  button {
    animation: none;
  }
}

/*
  If the browser understands the media query and the user
  explicitly hasn't set a preference, then use animations on buttons.
*/
@media (prefers-reduced-motion: no-preference) {
  button {
    /* `vibrate` keyframes are defined elsewhere */
    animation: vibrate 0.3s linear infinite both;
  }
}

Para ilustrar cómo trabajar con prefers-reduced-motion con JavaScript, imagina que definí una animación compleja con la API de Web Animations. Si bien el navegador activa las reglas de CSS de forma dinámica cuando las preferencias del usuario cambian, para las animaciones de JavaScript, tengo que escuchar los cambios de forma manual y, luego, detener de forma manual las animaciones que podrían estar en tránsito (o reiniciarlas si el usuario me permite):

const mediaQuery = window.matchMedia('(prefers-reduced-motion: reduce)');
mediaQuery.addEventListener('change', () => {
  console.log(mediaQuery.media, mediaQuery.matches);
  // Stop JavaScript-based animations.
});

Ten en cuenta que los paréntesis que encierran la consulta de medios real son obligatorios:

Qué no debes hacer
window.matchMedia('prefers-reduced-motion: reduce');
window.matchMedia('(prefers-reduced-motion: reduce)');

Trabajando con la búsqueda de medios desde <picture> contextos

Un caso de uso interesante es hacer que la reproducción de un AVIF, WebP o GIF animado dependa del atributo media. Si (prefers-reduced-motion: no-preference) se evalúa como true, es seguro mostrar la versión animada; de lo contrario, la versión estática:

<picture>
  <!-- Animated versions. -->
  <source
    srcset="nyancat.avifs"
    type="image/avif"
    media="(prefers-reduced-motion: no-preference)"
  />
  <source
    srcset="nyancat.gif"
    type="image/gif"
    media="(prefers-reduced-motion: no-preference)"
  />
  <!-- Static versions. -->
  <img src="nyancat.png" alt="Nyan cat" width="250" height="250" />
</picture>

Puedes ver el siguiente ejemplo. Intenta activar o desactivar las preferencias de movimiento de tu dispositivo para ver la diferencia.

Gato Nyan

Descubre las preferencias del usuario en el momento de la solicitud

El encabezado de sugerencia del cliente Sec-CH-Prefers-Reduced-Motion permite que los sitios obtengan las preferencias de movimiento del usuario de forma opcional en el momento de la solicitud, lo que permite a los servidores intercalar el CSS correcto por motivos de rendimiento.

Demostración

Creé una pequeña demostración basada en el increíble 🐈 gatos de estado HTTP de Rogério Vicente. Primero, tómate un momento para apreciar el chiste. Es gracioso y esperaré. Ahora que regresaste, te presentaré la demostración. Cuando te desplazas hacia abajo, cada gato de estado HTTP aparece de forma alternada del lado derecho o izquierdo. Es una animación de 60 FPS con fluidez, pero, como se describió anteriormente, es posible que a algunos usuarios no les guste o incluso que se maree con ella, por lo que la demostración está programada para respetar prefers-reduced-motion. Esto incluso funciona de forma dinámica, por lo que los usuarios pueden cambiar sus preferencias sobre la marcha, sin necesidad de volver a cargar el producto. Si un usuario prefiere un movimiento reducido, desaparecen las animaciones de revelación no necesarias y solo queda el movimiento de desplazamiento normal. En la siguiente presentación en pantalla, se muestra la demostración en acción:

Video de la app de demostración de prefers-reduced-motion

Conclusiones

Respetar las preferencias del usuario es clave para los sitios web modernos, y los navegadores exponen cada vez más funciones que permiten a los desarrolladores web hacerlo. Otro ejemplo lanzado es prefers-color-scheme, que detecta si el usuario prefiere un esquema de colores claro u oscuro. Puedes leer todo sobre prefers-color-scheme en mi artículo Hello Darkness, My Old Friend 名.

Actualmente, el grupo de trabajo de CSS está estandarizando más consultas de medios de preferencias del usuario, como prefers-reduced-transparency (detecta si el usuario prefiere una transparencia reducida), prefers-contrast (detecta si el usuario solicitó que el sistema aumente o disminuya el contraste entre los colores adyacentes) y inverted-colors (detecta si el usuario prefiere los colores invertidos).

(Contenido adicional) Cómo forzar la reducción de movimiento en todos los sitios web

No todos los sitios usarán prefers-reduced-motion o quizás no lo suficiente para tu gusto. Si, por alguna razón, quieres detener el movimiento en todos los sitios web, realmente puedes hacerlo. Una forma de lograrlo es insertar una hoja de estilo con el siguiente CSS en cada página web que visites. Existen varias extensiones de navegador (úsalas bajo tu responsabilidad) que lo permiten.

@media (prefers-reduced-motion: reduce) {
  *,
  ::before,
  ::after {
    animation-delay: -1ms !important;
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    background-attachment: initial !important;
    scroll-behavior: auto !important;
    transition-duration: 1ms !important;
    transition-delay: 1ms !important;
  }
}

La manera en que funciona es que el CSS anterior anula las duraciones de todas las animaciones y transiciones a tan poco tiempo que ya no se notan. Como algunos sitios web dependen de que se ejecute una animación para funcionar correctamente (tal vez porque un paso determinado depende de la activación del evento animationend), el enfoque animation: none !important; más radical no funcionaría. Incluso el truco anterior no garantiza su éxito en todos los sitios web (por ejemplo, no puede detener el movimiento que se inició a través de la API de Web Animations), así que asegúrate de desactivarlo cuando notes una falla.

Agradecimientos

Un saludo masivo a Stephen McGruer, que implementó prefers-reduced-motion en Chrome y, junto con Rob Dodson, también revisó este artículo. Hero image de Hannah Cauhepe en Unsplash.