
Core Web Vitals na prática: LCP, INP e CLS medidos e corrigidos
Core Web Vitals são as três métricas de experiência que o Google usa como sinal de ranqueamento: LCP (velocidade de carregamento), INP (responsividade a interações) e CLS (estabilidade visual). O detalhe que muita gente perde: a avaliação usa dados de usuários reais (CrUX), não o score sintético do Lighthouse no seu notebook. Este artigo mostra como medir corretamente e como corrigir cada métrica.
As três métricas e seus limites
| Métrica | O que mede | Bom | Ruim | Avaliado em |
|---|---|---|---|---|
| LCP — Largest Contentful Paint | Tempo até o maior elemento visível renderizar | ≤ 2,5 s | > 4,0 s | 75º percentil |
| INP — Interaction to Next Paint | Latência da pior interação da visita | ≤ 200 ms | > 500 ms | 75º percentil |
| CLS — Cumulative Layout Shift | Soma dos deslocamentos inesperados de layout | ≤ 0,1 | > 0,25 | 75º percentil |
INP substituiu o FID como métrica oficial em março de 2024. Diferente do FID (só o primeiro clique), o INP observa todas as interações da visita — é uma métrica bem mais exigente.
Medindo: dados de campo versus dados de laboratório
PageSpeed Insights mostra as duas fontes: 'dados reais de usuários' (CrUX, o que vale para ranqueamento) e 'diagnóstico de laboratório' (Lighthouse simulado, útil para debug). Para sites com pouco tráfego — sem dados CrUX próprios — o caminho é medir você mesmo com a biblioteca oficial web-vitals:
// npm install web-vitals
import { onLCP, onINP, onCLS } from "web-vitals";
function enviar(metrica: { name: string; value: number; rating: string }) {
// beacon: sobrevive ao fechamento da página
navigator.sendBeacon(
"/api/metricas",
JSON.stringify({
nome: metrica.name,
valor: metrica.value,
avaliacao: metrica.rating, // "good" | "needs-improvement" | "poor"
pagina: location.pathname,
})
);
}
onLCP(enviar);
onINP(enviar);
onCLS(enviar);Corrigindo LCP
O LCP divide-se em quatro fases: TTFB, carregamento do recurso, atraso de renderização e o paint em si. As causas mais comuns, em ordem de frequência:
- Imagem hero sem prioridade: adicione fetchpriority='high' e preload; nunca lazy-load na imagem LCP.
- CSS/JS bloqueante: inline do CSS crítico e defer no restante.
- TTFB alto: cache na borda (CDN), SSR/streaming e otimização de queries no servidor.
- Fontes atrasando texto: font-display: swap e preload das fontes principais.
<!-- Imagem LCP com prioridade máxima -->
<img src="/hero.avif" alt="Painel do produto" fetchpriority="high" width="1200" height="630" />
<!-- Ou via preload quando é background-image -->
<link rel="preload" as="image" href="/hero.avif" fetchpriority="high" />Corrigindo INP
INP ruim quase sempre significa main thread ocupada com JavaScript: handlers longos, renderizações pesadas síncronas ou hidratação gigantesca. As técnicas que funcionam: quebrar tarefas longas (>50 ms) cedendo ao event loop, adiar trabalho não-crítico e reduzir o JS enviado.
// Quebrando uma tarefa longa para a UI responder entre pedaços
async function processarItens(itens: Item[]) {
for (const item of itens) {
processar(item);
// cede a main thread: permite paint e input entre iterações
await new Promise((r) => setTimeout(r, 0));
}
}
// Trabalho não urgente fora do caminho crítico de interação
import { startTransition } from "react";
function onFiltroChange(valor: string) {
setTextoBusca(valor); // urgente: atualiza o input
startTransition(() => setResultados(filtrar(valor))); // pode esperar um frame
}Corrigindo CLS
Layout shift é sempre um elemento que aparece ou muda de tamanho depois do render inicial, empurrando conteúdo. As três fontes clássicas e suas correções:
- Imagens sem dimensão: sempre declare width e height (ou aspect-ratio) — o browser reserva o espaço antes de baixar a imagem.
- Anúncios e embeds: reserve um contêiner com min-height fixo, mesmo que o anúncio falhe.
- Fontes com métricas diferentes: use font-display: swap com fonte fallback ajustada (size-adjust) ou preload para trocar antes do primeiro paint.
/* Reservando espaço sem conhecer a altura exata */
img { width: 100%; height: auto; aspect-ratio: 16 / 9; }
/* Contêiner de anúncio com espaço garantido */
.slot-anuncio { min-height: 250px; }Não otimize contra o Lighthouse local. Um LCP de 1,2 s na sua máquina com cache quente diz pouco; o 75º percentil de usuários reais em celulares médios com 4G é o número que importa. Instrumente RUM primeiro, otimize depois.
Conclusão
Core Web Vitals não são um projeto único, são um regime contínuo: meça com dados reais, ataque a fase dominante de cada métrica (TTFB e prioridade de recursos no LCP, main thread no INP, espaço reservado no CLS) e proteja o resultado com budgets de performance no CI. Sites que tratam performance como feature permanente raramente precisam de 'projetos de otimização' emergenciais.
Perguntas frequentes
+Core Web Vitals realmente afetam o ranqueamento?
Sim, são um sinal confirmado de page experience, mas o Google é explícito: relevância de conteúdo pesa muito mais. Pense nos Vitals como critério de desempate e fator de conversão — páginas rápidas retêm mais usuários — não como atalho de SEO.
+Meu Lighthouse é 95 mas o CrUX está 'ruim'. Por quê?
O Lighthouse roda em condições simuladas na sua máquina; o CrUX reflete usuários reais com dispositivos e redes heterogêneas no 75º percentil. Dispositivos Android de entrada e redes 4G instáveis puxam a média para baixo. Otimize contra os dados de campo.
+Lazy-load de imagens ajuda ou atrapalha?
Ajuda em tudo abaixo da dobra; atrapalha no elemento LCP. A regra: loading='lazy' nunca na imagem hero, e fetchpriority='high' nela.
+INP alto só em páginas com muito JavaScript?
Predominantemente sim. As causas típicas são handlers de evento longos, re-renderizações grandes síncronas e bundles pesados demais na hidratação. Code splitting agressivo e quebra de tarefas longas resolvem a maioria dos casos.
Fontes consultadas
Revisão editorial: publicado em . Última revisão em . Conteúdo educativo, sem patrocínio das ferramentas citadas.
Leia também

Serverless: quando funções serverless valem a pena (e quando viram armadilha)
AWS Lambda, Cloudflare Workers e Vercel Functions comparados: modelo de custo, cold starts, limites de execução e os workloads onde serverless brilha ou falha.

Acessibilidade web (a11y) na prática: WCAG, ARIA e testes que funcionam
Guia técnico de acessibilidade: semântica HTML, quando (não) usar ARIA, contraste WCAG, navegação por teclado e testes automatizados com axe e Playwright.

PostgreSQL além do básico: índices, EXPLAIN e JSONB na prática
Aprenda a ler planos de execução com EXPLAIN ANALYZE, escolher entre B-tree, GIN e BRIN, e usar JSONB sem destruir a performance das suas queries.