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

A consulta de mídia de preferência reduzida com movimento detecta se o usuário solicitou o sistema operacional para minimizar a quantidade de animação ou movimento usado.

Nem todo mundo gosta de animações ou transições decorativas, e alguns usuários sentem enjoo ao se deparar com rolagem de paralaxe, efeitos de zoom e assim por diante. A consulta de mídia de preferência do usuário prefers-reduced-motion permite criar uma variante reduzida de movimento do seu site para usuários que expressaram essa preferência.

Compatibilidade com navegadores

  • 74
  • 79
  • 63
  • 10.1

Origem

Muito movimento na vida real e na Web

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

Vários pés de pessoas patinando no gelo.
Sobrecarga visual na vida real.

Ocasionalmente, o mesmo pode acontecer na Web: com anúncios que piscam, efeitos de paralaxe sofisticados, animações de revelação surpreendentes, reprodução automática de vídeos e assim por diante, a Web às vezes pode ser bastante pesada. Felizmente, ao contrário da vida real, existe 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 movimento reduzido. Isso pode incluir qualquer ação, desde evitar a reprodução automática de vídeos até desativar determinados efeitos puramente decorativos ou reformular completamente uma página para determinados usuários.

Antes de nos aprofundarmos no recurso, vamos parar e pensar para que as animações são usadas na Web. Se quiser, pule as informações básicas e acesse os detalhes técnicos abaixo.

Animação na Web

A animação geralmente é 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" em 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 simples, metadados contextuais e visualizações de imagens de baixa qualidade para ocupar muito tempo do usuário e tornar toda a experiência mais rápida. A ideia é dar contexto ao usuário sobre o que está por vir e, enquanto isso, carregar tudo o mais rápido possível.

Por fim, há efeitos decorativos, como gradientes animados, rolagem paralaxe, vídeos em segundo plano e muitos outros. Embora muitos usuários gostem dessas animações, outros não gostam porque se sentem distraídos ou desacelerados. Na pior das hipóteses, os usuários podem até sentir enjoo de movimento como se fosse uma experiência da vida real. Portanto, para eles, reduzir as animações é uma necessidade médica.

Distúrbio do espectro vestibular acionado por movimento

Alguns usuários sentem distração ou náusea com conteúdo animado. Por exemplo, animações de rolagem podem causar distúrbios vestibulares quando elementos diferentes do elemento 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 a uma taxa diferente dos elementos em primeiro plano. As reações do distúrbio vestibular (ouvido interno) incluem tontura, náusea e enxaqueca, e às vezes precisam de descanso na cama para se recuperar.

Remover movimento em sistemas operacionais

Muitos sistemas operacionais tiveram configurações de acessibilidade para especificar uma preferência por movimento reduzido por muito tempo. As capturas de tela abaixo mostram a preferência Reduzir movimento do macOS Mojave e a opção 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 aplicativos também podem e precisam respeitar essa configuração e remover todas as animações desnecessárias.

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

Remover movimento na Web

O nível 5 das consultas de mídia traz a preferência do usuário de movimento reduzido para a Web também. As consultas de mídia permitem que os autores testem e consultem valores ou recursos do user agent ou exibam o dispositivo independente do documento que está sendo 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 usado. Ela pode ter dois valores possíveis:

  • no-preference: indica que o usuário não tem preferência no sistema operacional subjacente. Este valor de palavra-chave é avaliado como false no contexto booleano.
  • reduce: indica que o usuário definiu uma preferência de 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 de contextos CSS e JavaScript

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

Para ilustrar ambos, digamos que eu tenha um botão de inscrição importante no qual quero que o usuário clique. Eu poderia definir uma animação "vibrar" atrativa, mas, como um bom cidadão da Web, só a reproduzirei para os usuários que concordam com as animações, mas não para todas as outras pessoas, que podem ser usuários que desativaram as 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, vamos imaginar 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 mudar, para animações JavaScript, preciso detectar alterações por conta própria e, em seguida, interromper manualmente minhas possíveis animações 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 é tornar a reprodução de um AVIF, WebP ou GIF animado dependente do atributo media. Se (prefers-reduced-motion: no-preference) for avaliado como true, será seguro exibir a versão animada. Caso contrário, a versão 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>

Confira o exemplo abaixo. Tente alternar as preferências de movimento do dispositivo para ver a diferença.

Gato Nyan

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

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

Demonstração

Criei uma pequena demonstração com base nos incríveis 🐈 status HTTP cats de Rogério Vicente. Primeiro, reserve um momento para apreciar a piada, é hilária e eu espero. Agora que você está de volta, vou apresentar a demonstração. Quando você rola para baixo, cada cat de status HTTP aparece alternadamente do lado direito ou do esquerdo. É uma animação suave de 60 QPS, mas, conforme descrito acima, alguns usuários podem não gostar ou até ficar enjoados com ela. Por isso, a demonstração é programada para respeitar prefers-reduced-motion. Isso funciona até mesmo de forma dinâmica, para que os usuários possam mudar a preferência imediatamente, sem precisar recarregar. Se um usuário preferir movimento reduzido, as animações de revelação desnecessárias desaparecerão, e apenas o movimento normal de rolagem permanecerá. O screencast abaixo mostra a demonstração em ação:

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

Conclusões

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

No momento, o grupo de trabalho de 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 ao sistema para 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 movimento reduzido em todos os sites

Nem todos os sites usarão prefers-reduced-motion e talvez não de modo significativo o suficiente para você. Se você, por qualquer motivo, quiser parar de movimento em todos os sites, isso é possível. Uma maneira de fazer isso é injetar uma folha de estilo com o CSS a seguir em cada página da Web que você visitar. Existem várias extensões de navegador (use por sua conta e risco) que permitem isso.

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

Isso funciona é que o CSS acima modifica a duração de todas as animações e transições para um período tão curto que elas não são mais perceptíveis. Como alguns sites dependem da execução de uma animação para funcionar corretamente (talvez porque uma determinada etapa dependa do disparo do evento animationend), a abordagem animation: none !important; mais radical não funcionará. Não há garantia de que a invasão acima terá sucesso em todos os sites (por exemplo, ela não pode interromper o movimento iniciado pela API Web Animations). Portanto, desative-a ao perceber falhas.

Agradecimentos

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