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

La consulta de medios de prefiere-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 de paralaje, los efectos de zoom y mucho más. La consulta de medios de preferencia del usuario prefers-reduced-motion te permite diseñar una variante de tu sitio con menos movimiento para los usuarios que expresaron esta preferencia.

Navegadores compatibles

  • Chrome: 74.
  • Edge: 79.
  • Firefox: 63.
  • Safari: 10.1.

Origen

Demasiada actividad en la vida real y en la Web

El otro día, estaba patinando sobre hielo con mis hijos. Era un día hermoso, el sol brillaba y la pista de hielo estaba llena de gente ⛸. El único problema es que no me llevo bien con las multitudes. Con tantos objetivos en movimiento, no logro enfocarme en nada y termino desorientado y con una sensación de sobrecarga visual completa, casi como si estuviera mirando un hormiguero 🐜.

Multitud de pies de personas que patinan sobre hielo.
Sobrecarga visual en la vida real.

En ocasiones, lo mismo puede suceder en la Web: con anuncios intermitentes, efectos de paralaje sofisticados, animaciones de revelación sorprendentes, videos que se reproducen automáticamente y mucho más, la Web puede ser bastante abrumadora… Afortunadamente, a diferencia de la vida real, hay una solución para eso. La consulta de medios CSS prefers-reduced-motion permite a los desarrolladores crear una variante de una página para los usuarios que prefieren un movimiento reducido. Esto puede incluir desde abstenerse de reproducir videos automáticamente hasta desactivar ciertos efectos puramente decorativos o rediseñar completamente una página para ciertos usuarios.

Antes de analizar la función, permíteme dar un paso atrás y pensar para qué se usan las animaciones en la Web. Si lo deseas, también puedes omitir la información de referencia y ir directamente a los detalles técnicos.

Animación en la Web

A menudo, se usa la animación para proporcionar comentarios al usuario, por ejemplo, para informarle que se recibió una acción y que se está procesando. Por ejemplo, en un sitio web de compras, un producto podría animarse 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 gran parte del tiempo del usuario y hacer que toda la experiencia se sienta más rápida. La idea es darle al usuario el contexto de lo que sucederá y, mientras tanto, cargar los elementos lo más rápido posible.

Por último, hay efectos decorativos, como gradientes animados, desplazamiento de paralaje, videos de fondo y muchos más. Si bien muchos usuarios disfrutan de esas animaciones, a algunos no les gustan porque los distraen o ralentizan. En el peor de los casos, los usuarios pueden incluso sufrir de mareos como si fuera una experiencia de la vida real, por lo que para estos usuarios reducir las animaciones es una necesidad médica.

Trastorno del espectro vestibular activado por el movimiento

Algunos usuarios sienten 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 de paralaje pueden causar trastornos vestibulares porque los elementos de fondo se mueven a una velocidad diferente a la de los elementos en primer plano. Las reacciones del trastorno vestibular (oído interno) incluyen mareos, náuseas y dolores de cabeza por migraña, y, a veces, requieren reposo en cama para recuperarse.

Cómo quitar el movimiento en los sistemas operativos

Muchos sistemas operativos tienen parámetros de configuración de accesibilidad para especificar una preferencia por reducir el movimiento desde hace mucho tiempo. En las siguientes capturas de pantalla, se muestra la preferencia Reducir movimiento de macOS Mojave y la preferencia Quitar animaciones de Android Pie. Cuando se marcan, estas preferencias hacen que el sistema operativo no use efectos decorativos, como animaciones de inicio de apps. Las aplicaciones también pueden y deben respetar este parámetro de configuración y quitar todas las animaciones innecesarias.

Pantalla de configuración de macOS con la casilla de verificación "Reduce el movimiento" marcada.
Pantalla de configuración de Android con la casilla de verificación "Quitar animaciones" marcada.

Cómo quitar el movimiento en la Web

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

  • no-preference: Indica que el usuario no estableció ninguna preferencia en el sistema operativo subyacente. Este valor de palabra clave se evalúa como false en el contexto booleano.
  • reduce: Indica que el usuario estableció una preferencia del sistema operativo que indica que las interfaces deben minimizar el movimiento o la animación, de preferencia hasta el punto en que se quite todo el movimiento no esencial.

Cómo trabajar 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.

Para ilustrar ambos, supongamos que tengo un botón de registro importante en el que quiero que haga clic el usuario. Podría definir una animación de "vibración" que capte la atención, pero como buen ciudadano web, solo la reproduciré para los usuarios que acepten explícitamente las animaciones, pero no para todos los demás, que pueden ser usuarios que inhabilitaron las animaciones o usuarios en navegadores que no entienden la consulta de contenido multimedia.

/*
  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 activará de forma dinámica las reglas CSS cuando cambie la preferencia del usuario, en el caso de las animaciones de JavaScript, debo detectar los cambios por mi cuenta y, luego, detener manualmente mis animaciones potencialmente en curso (o reiniciarlas si el usuario me lo 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 alrededor de la consulta de contenido multimedia real son obligatorios:

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

Cómo trabajar con la consulta de medios desde contextos de <picture>

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 del dispositivo para ver la diferencia.

El famoso 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 que los servidores incorporen el CSS correcto por motivos de rendimiento.

Demostración

Creé una pequeña demostración basada en los increíbles 🐈 gatos de estado HTTP de Rogério Vicente. Primero, tómate un momento para apreciar el chiste, es muy divertido. Esperaré. Ahora que regresaste, permíteme presentarte la demo. Cuando te desplazas, cada categoría de estado HTTP aparece de forma alternada desde el lado derecho o izquierdo. Es una animación fluida de 60 FPS, pero, como se describió antes, es posible que a algunos usuarios no les guste o incluso les provoque mareos, 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 su preferencia sobre la marcha, sin necesidad de volver a cargar la página. Si un usuario prefiere reducir el movimiento, las animaciones de revelación no necesarias desaparecen 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 demo de prefers-reduced-motion

Conclusiones

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

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

(Bonificación) Cómo forzar el movimiento reducido en todos los sitios web

No todos los sitios usarán prefers-reduced-motion, o tal vez no lo hagan de forma significativa. Si, por algún motivo, quieres detener el movimiento en todos los sitios web, puedes hacerlo. Una forma de lograr esto 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 propio riesgo) que permiten hacer esto.

@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;
  }
}

El CSS anterior anula las duraciones de todas las animaciones y transiciones a un tiempo tan corto 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 del disparo del evento animationend), el enfoque más radical de animation: none !important; no funcionaría. Incluso el hack anterior no es seguro que funcione en todos los sitios web (por ejemplo, no puede detener el movimiento que se inició con la API de Web Animations), así que asegúrate de desactivarlo cuando notes que se produce un error.

Agradecimientos

Un gran agradecimiento a Stephen McGruer, que implementó prefers-reduced-motion en Chrome y, junto con Rob Dodson, también revisó este documento. Imagen hero de Hannah Cauhepe en Unsplash.