Uma landing page pode carregar depressa e ainda parecer travada. O visitante toca no menu, escolhe um plano ou abre uma pergunta, mas a interface demora a mostrar a resposta. É esse tipo de atraso que o Interaction to Next Paint, o INP, ajuda a revelar.

O INP observa as interações de clique, toque e teclado durante a visita. A pontuação da página reflete uma das interações mais lentas, com tratamento de exceções em páginas que recebem muitas ações. O alvo recomendado é até 200 milissegundos no percentil 75, separado entre celular e desktop.

Esse número serve para priorizar. A correção exige descobrir onde o tempo foi gasto. Uma interação pode esperar a thread principal, executar JavaScript demais ou terminar o handler e ainda aguardar layout, pintura e composição.

Confirme que o problema está na interação

Não use INP para explicar qualquer sensação de lentidão. Separe os sintomas:

Sintoma Métrica ou evidência mais útil
conteúdo principal demora a aparecer LCP e suas fases
elementos mudam de lugar CLS e clusters de layout shift
clique demora a produzir o próximo frame INP e fases da interação
rolagem ou animação perde frames sem clique trace de Performance e frames lentos

O guia de Core Web Vitals explica como combinar campo e laboratório. Se o problema é uma animação contínua, use o artigo sobre animações lentas.

Entenda as três partes do INP

A documentação do web.dev sobre otimização de INP divide a latência em três partes.

Atraso de entrada

É o intervalo entre a ação da pessoa e o início do primeiro callback. A thread principal pode estar ocupada com JavaScript, análise de código, coleta de lixo ou renderização anterior.

Se o toque aconteceu durante uma tarefa longa, otimizar apenas o handler do botão não resolve tudo. Você precisa reduzir, adiar ou dividir o trabalho que já bloqueava a thread.

Duração do processamento

É o tempo usado pelos callbacks associados à interação. Entram aqui validação, filtros, renderização de componentes, serialização, consultas ao DOM e código de bibliotecas.

Um callback curto pode disparar trabalho síncrono em outra função. Leia a pilha completa no trace antes de atribuir a culpa ao listener visível no código.

Atraso de apresentação

Depois dos callbacks, o navegador ainda precisa produzir o próximo frame. Recalcular estilos, fazer layout e pintar uma região grande pode dominar essa fase.

Quando o handler parece barato, procure mudanças que alcançam muitos elementos, leituras de layout depois de escritas e efeitos visuais caros. O guia de DOM excessivo cobre essa parte com mais detalhe.

Reproduza uma ação real no DevTools

Abra a URL publicada no Chrome e entre no painel Performance. A visualização ao vivo registra as interações locais e mostra as fases de cada uma. A referência do painel Performance também marca interações acima de 200 milissegundos.

Escolha ações importantes para a conversão:

  • abrir e usar o menu no celular;
  • selecionar uma opção de preço;
  • expandir dúvidas frequentes;
  • preencher e enviar um formulário;
  • aplicar um filtro;
  • abrir ou fechar um modal;
  • avançar um carrossel manual.

Teste a primeira ação depois da carga e uma repetição. A primeira pode pagar custos de importação, inicialização ou montagem que as seguintes não pagam.

Registre a linha de base:

URL e Version:
dispositivo, viewport e CPU:
interação e alvo:
INP local:
atraso de entrada:
duração do processamento:
atraso de apresentação:
tarefa, função ou renderização dominante:

Repita pelo menos três vezes. Extensões, DevTools e processos do dispositivo introduzem ruído.

Corrija o atraso de entrada

Se a interação ficou esperando, descubra o que ocupava a thread principal imediatamente antes do evento.

As causas comuns em uma landing page são:

  • bundle grande sendo analisado e executado;
  • widget de chat ou analytics inicializando durante a primeira ação;
  • hidratação de uma área que não precisava ser interativa;
  • lista inteira sendo montada de uma vez;
  • callback de timer fazendo trabalho amplo;
  • script de terceiro rodando na mesma thread.

Carregue código quando a funcionalidade exigir. Adie integrações que não participam da primeira tarefa e divida tarefas longas em blocos que devolvam controle ao navegador.

O artigo sobre JavaScript na thread principal mostra como encontrar long tasks. Para integrações externas, siga o guia de custo de scripts de terceiros.

Reduza o trabalho do callback

Comece pelo caminho acionado pela pessoa. Não tente otimizar todo o JavaScript da rota ao mesmo tempo.

Antes de alterar:

button.addEventListener("click", () => {
const items = readAllItems();
const ranked = calculateEveryCombination(items);
renderResults(ranked);
saveHistory(ranked);
});

Uma revisão pode separar o que precisa acontecer antes do próximo frame:

button.addEventListener("click", () => {
showPendingState();
setTimeout(() => {
const ranked = calculateVisibleResults(readVisibleItems());
renderResults(ranked);
queueHistorySave(ranked);
}, 0);
});

Esse exemplo não é uma receita universal. O timer dá ao navegador uma oportunidade de processar outro trabalho, mas o bloco seguinte ainda pode ser longo. O ganho vem de mostrar um estado útil, reduzir o conjunto calculado e tirar a persistência do caminho crítico.

Revise também:

  • loops que percorrem itens invisíveis;
  • serialização de objetos grandes;
  • validação repetida a cada evento;
  • renderizações que recriam toda a seção;
  • listeners duplicados;
  • consultas ao DOM dentro de loops;
  • atualizações de estado que poderiam ser agrupadas.

Dê um frame ao navegador quando a tarefa é longa

Dividir uma tarefa só ajuda se o navegador puder processar entrada e renderizar entre os blocos. Um encadeamento de microtasks com Promise.resolve() pode continuar segurando a mesma rodada do event loop.

Use a opção compatível com o projeto e teste no trace. scheduler.yield() oferece uma forma explícita de ceder em navegadores compatíveis. Um setTimeout curto continua sendo uma alternativa comum quando o suporte necessário não existe.

Não pulverize uma operação em centenas de callbacks. Escolha limites com significado, como um lote de resultados, e confirme o custo total. Responsividade melhor com uma tarefa que nunca termina também é um bug.

Corte o atraso de apresentação

Se JavaScript termina cedo, mas o frame chega tarde, olhe para Style, Layout, Paint e Composite.

Procure:

  • classe aplicada perto da raiz e muitos elementos afetados;
  • leitura de offsetWidth ou getBoundingClientRect() depois de mudar estilos;
  • expansão que recalcula uma área grande;
  • sombra, filtro ou blur pintado em uma região extensa;
  • DOM duplicado para desktop e celular;
  • conteúdo inteiro trocado quando apenas um estado mudou.

Agrupe leituras antes das escritas. Limite o estado ao menor ramo necessário. Para movimento visual, teste transform e opacity quando preservarem o comportamento. Depois grave de novo, pois uma propriedade considerada barata pode continuar cara na composição real da página.

Não confunda feedback imediato com trabalho concluído

Uma resposta visual rápida precisa ser verdadeira. Não mostre “enviado” antes de o backend aceitar o formulário.

Você pode:

  1. desabilitar o botão com um estado acessível;
  2. mostrar que o envio começou no próximo frame;
  3. executar a requisição;
  4. apresentar sucesso ou erro quando houver resposta;
  5. devolver foco ao lugar correto.

Isso melhora a percepção sem mentir. Teste teclado, leitores de tela, toque duplo e falha de rede. O guia de teste de formulários cobre o fluxo completo.

Use dados de campo para escolher o alvo

Um trace local ajuda a corrigir uma interação conhecida. Dados reais mostram qual interação aparece em dispositivos, rotas e estados que você não reproduziu.

A versão com attribution da biblioteca web-vitals consegue registrar o alvo, o tipo de interação e as três fases do INP. O artigo sobre medição real de Core Web Vitals mostra como coletar esses dados sem enviar conteúdo do visitante.

Agrupe por rota, versão e classe de dispositivo. Não salve texto digitado, query strings com identificadores ou seletores que revelem dados pessoais.

Compare a mesma versão e o mesmo cenário

Depois da correção:

  1. gere a build final;
  2. repita as três gravações locais;
  3. teste a primeira interação e as seguintes;
  4. confirme o estado visual e acessível;
  5. publique no mesmo Site;
  6. verifique a URL pública;
  7. acompanhe dados de campo da nova versão.

No Site no Ar, consulte o contexto, altere os arquivos dentro de public/, chame deploy e acompanhe deploy_status até um estado terminal. A documentação de Publicação explica o contrato. O fluxo de republicação preserva a URL durante a comparação.

Prompt para investigar INP

Investigue o INP desta landing page sem publicar ainda.
URL e Version: [URL e commit]
Interações prioritárias: [menu, formulário, preços ou FAQ]
Cenário: [dispositivo, viewport e CPU]
1. Grave cada interação três vezes no painel Performance.
2. Separe atraso de entrada, processamento e apresentação.
3. Relacione a fase dominante à tarefa, função ou região renderizada.
4. Faça uma alteração pequena e preserve estados acessíveis.
5. Compare o mesmo cenário antes e depois.
6. Não envie conteúdo digitado nem identificadores para analytics.
7. Proponha a republicação somente com a evidência registrada.

INP melhora quando a página interrompe menos a pessoa. A meta não é fazer o handler desaparecer do trace. É entregar o próximo frame útil cedo, manter a ação correta e provar o resultado na rota que o público usa.