Animação de interface que explica a tela e some quando a pessoa pede menos movimento
Anime só o que mostra de onde algo veio, mantenha transições curtas e troque deslizamento por aparição direta quando o sistema pede menos movimento.
O Mercadinho Bom Preço ganhou um site novo: o carrinho desliza da direita com um leve quique, o banner gira sem parar, os cartões de produto sobem ao entrar na tela e o botão de compra pulsa. Na reunião, todo mundo achou moderno. Na primeira semana, chegaram dois e-mails de clientes dizendo que sentiam enjoo ao rolar a página, e o tempo médio até o primeiro clique em "Comprar" aumentou.
A resposta curta: animação boa responde a uma ação e explica uma mudança — de onde o painel veio, para onde o item foi. Ela é curta, não se repete sozinha e nada de conteúdo depende dela. E quando a pessoa ativa "reduzir movimento" no sistema, a página troca deslizamento e zoom por aparição direta ou um esmaecimento simples, usando a media query prefers-reduced-motion.
Por que movimento demais atrapalha
O olho humano é atraído por movimento antes de qualquer outra coisa. Isso é útil quando o movimento indica algo relevante: "o item entrou no carrinho, que está aqui". É prejudicial quando o movimento não diz nada, porque ele rouba a atenção do que a pessoa estava tentando ler. Um banner que gira a cada três segundos compete com a lista de preços o tempo inteiro.
Para uma parte das pessoas, o problema não é distração: é mal-estar físico. Quem tem distúrbios vestibulares pode sentir tontura e náusea com efeitos de paralaxe, zoom e deslizamentos grandes. Por isso os sistemas operacionais têm uma opção de reduzir movimento, e os navegadores expõem essa escolha ao CSS e ao JavaScript.
As diretrizes WCAG tratam do tema em dois critérios: o 2.2.2 (Pausar, Parar, Ocultar) pede um jeito de pausar conteúdo que se move sozinho por mais de cinco segundos junto de outro conteúdo, e o 2.3.3 (Animação a partir de Interações) pede que a animação disparada por interação possa ser desligada, salvo quando essencial. Se o seu problema é especificamente animação contínua, como carrossel e fundo animado, há um guia vizinho: animação contínua respeita quem pediu menos movimento. Este aqui trata das transições da interface.
Como decidir o que animar
- Liste cada movimento da tela e escreva, em uma frase, o que ele comunica.
- Corte o que não comunica nada. No Bom Preço, o botão pulsando e os cartões subindo saíram.
- Mantenha o que explica uma mudança de estado: o carrinho abrindo do lado onde fica o ícone, o item confirmado.
- Encurte. Transições de interface costumam funcionar bem na faixa de 150 a 300 ms. Mais que isso, a pessoa espera a animação acabar para continuar.
- Ofereça pausa para tudo que se move sozinho.
- Escreva a versão sem movimento primeiro e acrescente a animação só para quem não pediu menos.
- Teste com a preferência ligada.
CSS: movimento só para quem não pediu menos
Em vez de animar tudo e depois desligar, comece pela versão parada e acrescente movimento dentro de no-preference. Assim, navegadores e casos não previstos ficam no lado seguro.
.carrinho {
position: fixed;
inset: 0 0 0 auto;
width: min(380px, 100%);
visibility: hidden;
opacity: 0;
}
.carrinho.aberto {
visibility: visible;
opacity: 1;
}
@media (prefers-reduced-motion: no-preference) {
.carrinho {
transform: translateX(100%);
transition: transform 220ms ease-out, opacity 220ms ease-out, visibility 0s linear 220ms;
}
.carrinho.aberto {
transform: translateX(0);
transition: transform 220ms ease-out, opacity 220ms ease-out, visibility 0s;
}
}
@media (prefers-reduced-motion: reduce) {
.carrinho {
transition: opacity 120ms linear;
}
}
Para quem não pediu menos movimento, o carrinho desliza da direita em 220 ms, mostrando que veio do ícone no canto. Para quem pediu, ele apenas esmaece rapidamente no lugar. Reduzir movimento não precisa significar zero transição: uma troca de opacidade curta não provoca o desconforto de um deslocamento grande. O visibility garante que, fechado, o painel não receba foco nem cliques.
JavaScript: a mesma preferência
Rolagem suave e animações feitas em JavaScript não obedecem à media query do CSS sozinhas. Consulte a preferência:
const reduzir = window.matchMedia('(prefers-reduced-motion: reduce)');
function irPara(elemento) {
elemento.scrollIntoView({ behavior: reduzir.matches ? 'auto' : 'smooth', block: 'start' });
}
function confirmarItem(botao) {
botao.textContent = 'Adicionado';
if (!reduzir.matches) {
botao.animate(
[{ transform: 'scale(1)' }, { transform: 'scale(1.06)' }, { transform: 'scale(1)' }],
{ duration: 180, easing: 'ease-out' }
);
}
}
Repare que a informação está no texto ("Adicionado"), não no movimento. Com a animação desligada, a pessoa continua sabendo que o item entrou no carrinho. Esse é o teste mais importante de toda animação.
Pausa para o que se move sozinho
O banner do Bom Preço não gira mais sozinho para quem pediu menos movimento, e para os demais ganhou um botão "Pausar" visível, que também para quando o foco do teclado entra no banner. Rotação automática que não pode ser parada é exatamente o caso do critério 2.2.2.
Como testar a preferência de reduzir movimento
Ative no sistema e use a página de verdade. No Windows, a opção fica nas configurações de acessibilidade, em efeitos visuais, como "Efeitos de animação". No macOS e no iOS, em Acessibilidade, como "Reduzir movimento". No Android, também em acessibilidade, com o nome "Remover animações" na maioria das versões. Os nomes mudam um pouco entre versões, mas a busca das configurações encontra.
Para testar sem mexer no sistema, o painel Rendering do DevTools do Chrome permite emular a media feature prefers-reduced-motion. Abra a página, emule reduce e percorra os fluxos principais: abrir menu, adicionar ao carrinho, finalizar compra, rolar até o rodapé.
A animação também afeta desempenho. Anime transform e opacity, que os navegadores conseguem compor sem recalcular o layout da página inteira; animar width, top ou margin costuma travar em celular modesto. Mais sobre velocidade em site mais rápido: por onde começar.
Erros comuns
- Animar tudo que entra na tela. A página parece ocupada e a pessoa espera os elementos pararem para ler.
- Transições longas em ações frequentes. Um menu de 600 ms aberto vinte vezes por dia vira atraso perceptível.
- Ignorar
prefers-reduced-motion. Quem tem sensibilidade vestibular sente desconforto ou abandona o site. - Informação que só existe no movimento. Com a animação desligada, a confirmação some e a pessoa clica de novo.
- Carrossel automático sem pausa. Compete com a leitura e descumpre o critério 2.2.2 das WCAG.
- Animar propriedades de layout. Engasgos em aparelhos modestos, justamente onde a paciência é menor.
Checklist
- Cada animação tem uma frase dizendo o que ela comunica.
- Transições de interface estão por volta de 150 a 300 ms.
- O CSS acrescenta movimento dentro de
prefers-reduced-motion: no-preference. - Animações em JavaScript consultam
matchMediaantes de rodar. - Tudo que se move sozinho tem botão de pausa.
- Com a preferência ligada, nenhuma informação desaparece.
- As animações usam
transformeopacity.
Ligue "reduzir movimento" no seu sistema agora e faça uma compra ou cadastro completo no seu site: alguma coisa ainda desliza, gira ou some sem você saber se a ação deu certo?
Referência: https://jitter.video/