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 ou transições decorativas, e alguns usuários sentem enjoo de movimento ao se deparar com paralaxe, efeitos de zoom etc. A consulta de mídia de preferência do usuário prefers-reduced-motion permite criar uma variante de redução 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, eu estava patinando no gelo com meus filhos. Era um dia lindo, com sol brilhando, e a pista de patinação estava lotada de pessoas ⛸. O único problema: não me adapto bem à multidão. Com tantos alvos em movimento, eu não consigo me concentrar em nada e acabo 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 que piscam, efeitos de paralaxe extravagantes, animações de revelação surpreendentes, vídeos com reprodução automática e assim por diante, a Web às vezes pode ficar sobrecarregado... Felizmente, diferentemente 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 movimento reduzido. Isso pode incluir desde evitar a reprodução automática de vídeos, desativar alguns efeitos puramente decorativos até recriar completamente uma página para determinados usuários.

Antes de abordar o recurso, vamos pensar sobre para que as animações são usadas na Web. Se quiser, você também pode pular as informações básicas e passar direto para os detalhes técnicos abaixo.

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 poderia 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 combinação de telas esqueleto, metadados contextuais e visualizações de imagens de baixa qualidade para ocupar muito 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 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 delas porque se sentem distraídas ou desaceleradas. Na pior das hipóteses, os usuários podem até sofrer de enjoo 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 devido a conteúdo animado. Por exemplo, as animações de rolagem podem causar distúrbios vestibulares quando elementos diferentes do principal associado à rolagem se movem muito. Por exemplo, as animações de rolagem paralaxe podem causar distúrbios vestibulares porque os elementos de fundo se movem em uma taxa diferente dos elementos de primeiro plano. As reações vestibulares (ouvido interno) incluem tontura, náusea e enxaqueca, e, às vezes, exigem repouso na cama para se recuperar.

Remover movimento nos 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 abaixo mostram a preferência Reduzir movimento do macOS Mojave e 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.
Uma captura de tela da tela de configurações do Android com a caixa de seleção "Remover animações" marcada.

Remover movimento na Web

As consultas de mídia de nível 5 também trazem 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 user agent ou do dispositivo de exibição 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. Pode usar dois valores possíveis:

  • no-preference: indica que o usuário não deu 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 de sistema operacional indicando que as interfaces precisam minimizar o movimento ou a animação, de preferência ao 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 CSS e em JavaScript.

Para ilustrar ambos, digamos que eu tenha um botão importante de inscrição no qual quero que o usuário clique. Eu poderia definir uma animação "vibrar" que chame a atenção, mas, como um bom usuário da Web, vou reproduzi-la apenas para usuários que concordam explicitamente com as animações, mas não para os demais, 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 defini 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 as alterações e, em seguida, interromper manualmente minhas animações potencialmente 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 conferir 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 in-line 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, tire um momento para apreciar a piada, é hilária e eu vou esperar. Agora que você voltou, vou apresentar a demonstração. Quando você rola para baixo, cada status HTTP aparece alternadamente no lado direito ou esquerdo. É uma animação de 60 QPS suave, mas, conforme descrito acima, 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 até mesmo dinamicamente, para que os usuários possam mudar a preferência deles imediatamente, sem precisar recarregar. Se um usuário preferir um movimento reduzido, as animações de revelação desnecessárias vão desaparecer, e apenas o movimento de rolagem normal será deixado. 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 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. Você pode ler tudo sobre prefers-color-scheme no meu artigo Hello Darkness, My Old Friend 🌒.

No momento, 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 uma transparência reduzida), prefers-contrast (detecta se o usuário pediu ao sistema para aumentar ou diminuir o contraste entre cores adjacentes) e inverted-colors (detecta se o usuário prefere cores invertidas).

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

Nem todos os sites usam o prefers-reduced-motion ou talvez não sejam suficientes para você. Se você quiser, por qualquer motivo, interromper a movimentação em todos os sites, isso é possível. Uma maneira de fazer isso é injetar uma folha de estilo com o seguinte CSS 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;
  }
}

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 de uma animação para funcionar corretamente (talvez porque uma determinada etapa depende do acionamento do animationendevento), a abordagem mais radical animation: none !important; não funcionaria. Nem mesmo a invasão acima tem garantia de sucesso em todos os sites. Por exemplo, ela não pode interromper o movimento iniciado pela API Web Animations (link em inglês). Portanto, desative-a quando perceber uma interrupção.

Agradecimentos

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