O que trava a interface: as três etapas que o navegador refaz
"O site está travando no celular" é um dos relatos mais frustrantes que existem, porque parece problema de máquina fraca e quase nunca é. Na maioria dos casos que investiguei, a causa era específica e barata de corrigir: alguma coisa animando a propriedade errada.
Para consertar sem chutar, ajuda entender o que o navegador faz sessenta vezes por segundo.
As três etapas
Para cada quadro, o navegador pode precisar refazer até três coisas:
- Layout — calcular posição e tamanho de cada elemento. É a etapa mais cara, porque mexer num elemento pode obrigar a recalcular os vizinhos, e às vezes a página inteira.
- Paint — pintar os pixels: cores, bordas, sombras, texto.
- Composite — juntar as camadas já pintadas na tela. É a mais barata e pode acontecer fora da linha principal.
O ponto que muda tudo: a propriedade que você anima determina em qual etapa o trabalho começa. E o trabalho vem em cascata — mexer no layout obriga a repintar e recompor também.
O mapa de custo
| Propriedade | Refaz | Custo |
|---|---|---|
transform, opacity | composite | Barato |
background-color, box-shadow, filter | paint + composite | Médio |
width, height, top, left, margin, padding | layout + paint + composite | Caro |
Na prática isso vira uma regra curta: para mover, use translate em vez de top ou left. Para redimensionar, use scale em vez de width e height. O efeito visual é o mesmo; o custo não é.
Veja um elemento se movendo com transform — a versão barata:
E um que anima altura, mexendo no layout a cada quadro:
Nas duas, isolado, você não vê diferença. É esse o problema — o custo só aparece quando multiplica.
Por que "funciona na minha máquina"
Seu computador de trabalho tem folga de sobra. Ele absorve trabalho desperdiçado sem reclamar, e você entrega achando que está tudo bem.
O celular de quem usa o produto tem processador mais fraco, memória menor e às vezes está com bateria em modo de economia — que reduz a frequência do processador de propósito. É lá que os mesmos sessenta quadros por segundo viram vinte.
Uma animação cara não trava nada. Quarenta na mesma tela travam — e sempre no aparelho de quem você menos queria decepcionar.
O multiplicador é quase sempre lista. Um card com sombra animada no hover é irrelevante. Uma grade com quarenta cards, cada um com sombra animada, é outra história — e é exatamente o padrão que aparece em catálogo, marketplace e painel.
Os quatro padrões que mais aparecem
1. Sombra animada em lista
box-shadow força repintura de uma área maior que o próprio elemento, porque a sombra vaza para fora. Em lista longa, é o campeão de travamento.
Saída: deixe a sombra fixa e anime transform: translateY() — a sensação de elevação vem do deslocamento. Ou coloque a sombra num pseudo-elemento e anime só a opacidade dele.
2. Animar left e top
Herança de tutorial antigo. Toda vez que o valor muda, o navegador recalcula a posição — e, dependendo do contexto, a dos vizinhos também.
Saída: transform: translate(). Aceita as mesmas unidades e resolve na etapa final.
3. filter em elemento grande
Desfoque é caro por natureza: o navegador precisa ler os pixels ao redor de cada ponto. Num elemento pequeno, tudo bem. Numa área grande, ou com vários ao mesmo tempo, o custo dispara.
A peça abaixo usa desfoque na entrada. Vale no destaque principal da página — não em lista:
4. Animar cor de fundo em muitos elementos
Mais barato que layout, mas ainda é repintura. Em uma tabela com centenas de linhas que mudam de cor ao passar o mouse, aparece.
Saída: quando possível, sobreponha uma camada com opacidade animada em vez de trocar a cor.
Como medir em vez de adivinhar
Palpite sobre performance costuma estar errado. Duas checagens rápidas:
- Grave um perfil nas ferramentas de desenvolvedor enquanto reproduz o travamento. Barras longas na linha do tempo mostram onde o tempo vai — e se aparece "layout" ou "recalculate style" repetidamente durante uma animação, achou o culpado.
- Reduza a velocidade do processador nas próprias ferramentas. É a forma mais honesta de sentir o que o público sente, sem precisar de um aparelho antigo na mesa.
Faça isso antes de otimizar. Já vi bastante tempo gasto deixando animação mais eficiente quando o gargalo real era uma imagem enorme carregando junto.
Duas ferramentas que ajudam — e uma que atrapalha
will-change avisa o navegador que uma propriedade vai mudar, e ele prepara uma camada separada. Usado com moderação, resolve engasgo no início da animação. Usado em tudo, consome memória e piora — cada camada tem custo. Aplique no elemento específico, pouco antes de animar.
content-visibility permite pular a renderização do que está fora da tela. Em página longa, o ganho é grande.
E a que atrapalha: transform: translateZ(0) como truque genérico. Era o jeito antigo de forçar aceleração. Hoje o navegador decide melhor sozinho, e espalhar isso pelo código cria dezenas de camadas desnecessárias — que é justamente o problema que você queria evitar.
O caso em que animar caro é o certo
Nada disso significa proibição. Um painel que expande precisa empurrar o conteúdo de baixo — é isso que a interface está comunicando. Fazer com transform deixaria os elementos sobrepostos.
A diferença é intenção: animar layout porque o layout é o ponto, uma vez na tela, com duração curta. Não por hábito, em quarenta elementos, porque foi o primeiro jeito que funcionou.
O resumo em quatro linhas
- Para mover:
translate. Para crescer:scale. - Sombra e desfoque: fixos, ou animados uma vez só na tela.
- Desconfie sempre que a animação estiver dentro de lista.
- Meça com o processador reduzido antes de decidir que está bom.
São quatro decisões que não custam tempo nenhum se tomadas enquanto você escreve — e custam bastante quando viram relato de "o site trava no celular" três meses depois.
As peças usadas aqui estão no acervo de animações, com o comentário de custo no próprio código de cada uma.