Trilha 11 · Como um navegador funciona

Performance: reflow, repaint e composite

Por que algumas animações travam e outras são suaves? A diferença está em qual parte do pipeline de renderização é acionada — e como evitar as mais custosas.

① Intuição

A diferença entre 60fps e 6fps

O browser tenta renderizar a 60 frames por segundo — um novo frame a cada 16ms. Se uma operação JavaScript ou CSS levar mais que isso, o frame é perdido e o usuário sente "jank" (travamento). A maioria das travagens acontece por reflow desnecessário: mudanças que forçam o browser a recalcular posições e tamanhos de elementos.

Entender quais propriedades CSS e quais operações JS disparam cada fase do pipeline é a diferença entre uma animação fluida e uma que trava. A regra de ouro: use transform e opacity para animações — elas vão direto para a GPU.

Long Tasks: qualquer tarefa no thread principal que dure mais de 50ms é considerada uma "Long Task" e impede o browser de responder a inputs. Divida trabalho pesado usando setTimeout(fn, 0) ou scheduler.yield() para ceder o thread periodicamente.
② Visualização interativa

Explore o custo de cada propriedade

Clique nas categorias e depois nas propriedades para ver o que cada uma dispara no pipeline de renderização e por quê.

CompositeMais rápido — só GPU

Estas propriedades são processadas inteiramente na GPU pelo thread do compositor, sem acionar o thread principal do browser. Animações a 60fps são alcançáveis.

PROPRIEDADES
DETALHE
transform
Mover, girar e escalar na GPU. Não afeta outros elementos — ideal para animações de posição e tamanho.
Composite
③ Explicação técnica

Forced Synchronous Layout

// Forced Synchronous Layout — o pior anti-pattern

// ✗ MAU: leitura depois de escrita em loop = reflow por iteração
const elements = document.querySelectorAll(".card");
for (const el of elements) {
  el.style.width = el.offsetWidth + 10 + "px";  // read → reflow → write, 100x!
}

// ✓ BOM: leia tudo, depois escreva tudo (batch reads/writes)
const widths = Array.from(elements).map(el => el.offsetWidth);  // leitura em batch
elements.forEach((el, i) => el.style.width = widths[i] + 10 + "px");  // escrita em batch

// Melhor ainda: FastDOM (biblioteca) agenda leituras/escritas no frame certo

Ferramentas de diagnóstico

# Ferramentas para medir performance

# 1. Performance API (JavaScript)
performance.now()                          # timestamp de alta resolução (ms)
performance.mark("inicio")
performance.mark("fim")
performance.measure("duracao", "inicio", "fim")

# 2. PerformanceObserver (métricas automáticas)
new PerformanceObserver((list) => {
  list.getEntries().forEach(e => console.log(e.name, e.startTime));
}).observe({ type: "layout-shift", buffered: true });

# 3. DevTools Performance tab
# F12 → Performance → Record → interagir → Stop
# Identifica: Long Tasks (>50ms), Layout, Paint, Script

# 4. Lighthouse (DevTools → Lighthouse)
# Pontuação 0-100 para Performance, Acessibilidade, SEO
# Mostra oportunidades específicas de melhoria
Regra das Listas de FastDOM: em qualquer frame, faça todas as leituras de layout primeiro, depois todas as escritas. Nunca alterne entre leitura e escrita em loop — isso força reflow a cada iteração. A biblioteca fastdom (npm) automatiza esse padrão com uma API de agendamento.
④ Projeto para programar

Meça e otimize uma animação

Mini projeto: crie uma animação de 50 divs voando pela tela usando setInterval + left/top. Meça o FPS com performance.now(). Depois reimplemente com requestAnimationFrame + transform e compare.

Projeto principal: grave um perfil de performance no DevTools de uma página com scroll. Identifique a maior Long Task. Reescreva o código responsável para não bloquear o thread principal por mais de 16ms.

Desafio extra: use o Layout Instability API e o Largest Contentful Paint observer para criar um "Performance HUD" — um overlay que mostra LCP, CLS e FPS em tempo real sobre qualquer página, usando apenas um content script de extensão.

⑤ Exercícios rápidos

Teste sua intuição

Qual das mudanças de CSS abaixo dispara um reflow (recalcular posições)?
Para uma animação de movimento suave a 60fps, qual CSS usar?
O que é um Forced Synchronous Layout?
⑥ Aplicações no mundo real

Onde você encontra isso

🎬

Framer Motion

Biblioteca de animações do React que usa exclusivamente transform e opacity para animações de layout. Internally usa o FLIP technique (First, Last, Invert, Play) para animar mudanças de posição sem reflow.

📊

Charts e D3

D3.js pode ser lento com muitos elementos SVG. O padrão moderno é usar WebGL (via regl ou Three.js) para renderizar grandes quantidades de dados diretamente na GPU, bypassing o pipeline DOM completamente.

🏎️

INP (Interaction to Next Paint)

A nova métrica Core Web Vital mede o tempo desde um clique/teclado até o próximo pixel na tela. Um INP ruim (>200ms) quase sempre tem Long Tasks bloqueando o thread entre o evento e o render.

⚙️

CSS Containment

contain: strict diz ao browser que mudanças dentro do elemento não afetam elementos fora. Isso limita o escopo do reflow a uma subárvore — crucial para componentes reutilizáveis em páginas grandes.

← Anterior: Segurança ✓ Concluir trilha: Como um navegador funciona