prefere-redução-movimento: às vezes, menos movimento é mais

A consulta de mídia "prefers-reduced-motion" detecta se o usuário solicitou que o sistema operacional minimize a quantidade de animação ou movimento usado.

Nem todo mundo gosta de animações decorativas ou transições, e alguns usuários podem sentir enjoo de movimento ao se depararem com rolagem de paralaxe, efeitos de zoom e muito mais. A consulta de mídia de preferência do usuário prefers-reduced-motion permite projetar uma variante com movimento reduzido do seu site para usuários que expressaram essa preferência.

Compatibilidade com navegadores

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

Origem

Muito movimento na vida real e na Web

Outro dia, eu estava patinando no gelo com meus filhos. Estava um dia lindo, o sol estava brilhando, e a pista de gelo estava lotada de gente ⛸. O único problema com isso: eu não lido bem com multidões. Com tantos alvos em movimento, não consigo me concentrar em nada e acabo me sentindo perdida e com uma sensação de sobrecarga visual completa, quase como olhar para um formigueiro 🐜.

Multidão de pés de pessoas patinando no gelo.
Sobrecarga visual na vida real.

Às vezes, o mesmo pode acontecer na Web: com anúncios intermitentes, efeitos de paralaxe sofisticados, animações de revelação surpreendentes, vídeos que são reproduzidos automaticamente e muito mais, a Web às vezes pode ser bastante cansativa. Felizmente, ao contrário da vida real, há uma solução para isso. A consulta de mídia CSS prefers-reduced-motion permite que os desenvolvedores criem uma variante de uma página para usuários que preferem movimentos reduzidos. Isso pode ser desde evitar a reprodução automática de vídeos até desativar alguns efeitos puramente decorativos ou redesenhar completamente uma página para determinados usuários.

Antes de entrar no recurso, vamos dar um passo atrás e pensar em como as animações são usadas na Web. Se quiser, você também pode pular as informações de contexto e ir direto para os detalhes técnicos.

Animação na Web

Muitas vezes, a animação é usada para fornecer feedback ao usuário, por exemplo, para informar que uma ação foi recebida e está sendo processada. Por exemplo, em um site de compras, um produto pode ser animado para "voar" para um carrinho de compras virtual, representado como um ícone no canto superior direito do site.

Outro caso de uso envolve o uso de movimento para hackear a percepção do usuário usando uma mistura de telas esqueleto, metadados contextuais e visualizações de imagens de baixa qualidade para ocupar muito do tempo do usuário e fazer com que toda a experiência pareça mais rápida. A ideia é dar contexto ao usuário sobre o que está por vir e, ao mesmo tempo, carregar as coisas o mais rápido possível.

Por fim, há efeitos decorativos, como gradientes animados, rolagem paralaxe, vídeos de plano de fundo e vários outros. Embora muitas pessoas gostem dessas animações, algumas não gostam delas porque se sentem distraídos ou lentos. Na pior das hipóteses, os usuários podem até sofrer de enjoo como se fosse uma experiência real. Portanto, para esses usuários, reduzir animações é uma necessidade médica.

Distúrbio do espectro vestibular acionado por movimento

Alguns usuários sentem distração ou náusea devido a conteúdo animado. Por exemplo, animações de rolagem podem causar distúrbios vestibulares quando elementos diferentes do principal associado à rolagem se movem muito. Por exemplo, animações de rolagem de paralaxe podem causar distúrbios vestibulares porque os elementos de segundo plano se movem em uma taxa diferente dos elementos de primeiro plano. As reações de distúrbios vestibulares (do ouvido interno) incluem tontura, náusea e enxaqueca, e às vezes exigem repouso para se recuperar.

Remover o movimento em sistemas operacionais

Muitos sistemas operacionais têm configurações de acessibilidade para especificar uma preferência por movimento reduzido por muito tempo. As capturas de tela a seguir mostram a preferência Reduzir movimento do macOS Mojave e a preferência Remover animações do Android Pie. Quando marcadas, essas preferências fazem com que o sistema operacional não use efeitos decorativos, como animações de inicialização de apps. Os próprios apps podem e devem respeitar essa configuração e remover todas as animações desnecessárias.

Tela de configurações do macOS com a caixa de seleção "Reduzir movimento" marcada.
Tela de configurações do Android com a caixa de seleção "Remover animações" marcada.

Remover movimento na Web

O Media Queries Level 5 também traz a preferência do usuário de movimento reduzido para a Web. As consultas de mídia permitem que os autores testem e consultem valores ou recursos do agente do usuário ou do dispositivo de exibição, independentemente do documento renderizado. A consulta de mídia prefers-reduced-motion é usada para detectar se o usuário definiu uma preferência do sistema operacional para minimizar a quantidade de animação ou movimento que ele usa. Ele pode ter dois valores possíveis:

  • no-preference: indica que o usuário não fez nenhuma preferência no sistema operacional subjacente. Esse valor de palavra-chave é avaliado como false no contexto booleano.
  • reduce: indica que o usuário definiu uma preferência do sistema operacional indicando que as interfaces precisam minimizar o movimento ou a animação, de preferência até o ponto em que todos os movimentos não essenciais são removidos.

Como trabalhar com a consulta de mídia em contextos de CSS e JavaScript

Assim como em todas as consultas de mídia, prefers-reduced-motion pode ser verificado em um contexto CSS e em JavaScript.

Para ilustrar os dois, suponha que eu tenha um botão de inscrição importante em que quero que o usuário clique. Eu poderia definir uma animação de "vibração" que chama a atenção, mas, como um bom cidadão da Web, só a mostro para usuários que aceitam explicitamente animações, mas não para todos, que podem ser usuários que desativaram animações ou usuários em navegadores que não entendem a consulta de mídia.

/*
  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 como trabalhar com prefers-reduced-motion com JavaScript, imagine que eu tenha definido uma animação complexa com a API Web Animations. Embora as regras de CSS sejam acionadas dinamicamente pelo navegador quando a preferência do usuário muda, para animações JavaScript, preciso detectar as mudanças e interromper manualmente as animações que estão em andamento (ou reiniciá-las se o usuário permitir):

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

Os parênteses ao redor da consulta de mídia real são obrigatórios:

O que não fazer
window.matchMedia('prefers-reduced-motion: reduce');
O que fazer
window.matchMedia('(prefers-reduced-motion: reduce)');

Como trabalhar com a consulta de mídia de contextos <picture>

Um caso de uso interessante é fazer com que a reprodução de um AVIF, WebP ou GIF animado dependa do atributo media. Se (prefers-reduced-motion: no-preference) for avaliado como true, será possível exibir a versão animada. Caso contrário, a versão estática será mostrada:

<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>

Confira o exemplo a seguir. Tente ativar as preferências de movimento do dispositivo para notar a diferença.

O famoso Nyan Cat.

Descobrir as preferências do usuário no momento da solicitação

O cabeçalho de sugestão de cliente Sec-CH-Prefers-Reduced-Motion permite que os sites recebam as preferências de movimento do usuário opcionalmente no momento da solicitação, permitindo que os servidores inlinem o CSS correto por motivos de performance.

Demonstração

Criei uma pequena demonstração com base nos incríveis gatos de status HTTP 🐈 de Rogério Vicente. Primeiro, aproveite a piada, ela é hilária, e eu vou esperar. Agora que você voltou, vou apresentar a demonstração. Quando você rola, cada categoria de status HTTP aparece alternadamente no lado direito ou esquerdo. É uma animação de 60 QPS suave, mas, como descrito anteriormente, alguns usuários podem não gostar dela ou até mesmo ficar com enjoo do movimento. Por isso, a demonstração é programada para respeitar prefers-reduced-motion. Isso funciona de forma dinâmica, para que os usuários possam mudar a preferência rapidamente, sem precisar recarregar. Se um usuário preferir um movimento reduzido, as animações de revelação desnecessárias serão removidas, e apenas o movimento de rolagem normal será mantido. O screencast a seguir mostra a demonstração em ação:

Vídeo da demonstração do app prefers-reduced-motion

Conclusões

Respeitar as preferências do usuário é fundamental para os sites modernos, e os navegadores estão expondo cada vez mais recursos para que os desenvolvedores Web possam fazer isso. Outro exemplo lançado é o prefers-color-scheme, que detecta se o usuário prefere um esquema de cores claro ou escuro. Leia tudo sobre prefers-color-scheme no meu artigo Hello Darkness, My Old Friend 🌒.

O Grupo de Trabalho do CSS está padronizando mais consultas de mídia de preferência do usuário, como prefers-reduced-transparency (detecta se o usuário prefere transparência reduzida), prefers-contrast (detecta se o usuário pediu para o sistema aumentar ou diminuir a quantidade de contraste entre cores adjacentes) e inverted-colors (detecta se o usuário prefere cores invertidas).

(Bônus) Forçar o movimento reduzido em todos os sites

Nem todos os sites usam prefers-reduced-motion ou talvez não o suficiente para você. Se, por algum motivo, você quiser desativar a animação em todos os sites, é possível fazer isso. Uma maneira de fazer isso é injetar uma folha de estilo com o CSS abaixo em todas as páginas da Web que você visitar. Existem várias extensões de navegador que permitem isso (use por sua conta e risco).

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

O CSS anterior substitui as durações de todas as animações e transições para um tempo tão curto que elas não são mais perceptíveis. Como alguns sites dependem de uma animação para funcionar corretamente (talvez porque uma determinada etapa depende do disparo do evento animationend), a abordagem mais radical de animation: none !important; não funciona. Mesmo o hack anterior não tem garantia de sucesso em todos os sites (por exemplo, ele não pode interromper o movimento iniciado usando a API Web Animations). Portanto, desative-o quando notar uma falha.

Agradecimentos

Um agradecimento a Stephen McGruer, que implementou a prefers-reduced-motion no Chrome e, junto com Rob Dodson, também analisou este documento. Imagem principal de Hannah Cauhepe no Unsplash.