Um botão que muda de lugar quando a imagem chega não parece um detalhe de performance. Para quem estava prestes a tocar, é um erro de interface.

Landing pages criadas por IA costumam combinar hero responsiva, fontes web, animações, embeds, banners e formulários. Se o HTML não reserva espaço para cada parte, o navegador monta uma primeira versão e reorganiza a página conforme os recursos aparecem.

Cumulative Layout Shift, ou CLS, mede esses deslocamentos inesperados. Corrigir a métrica exige descobrir qual elemento se moveu, qual conteúdo causou o movimento e em que momento da visita ele ocorreu.

O que conta como layout shift

Um layout shift acontece quando um elemento visível muda sua posição inicial entre dois frames. A pontuação considera quanto da viewport foi afetado e a distância do movimento.

Nem toda mudança entra na pontuação. A API marca hadRecentInput quando o deslocamento acontece até 500 ms depois de uma entrada qualificada, como clique, toque ou tecla; esses shifts ficam fora do CLS. O navegador aplica essa janela de tempo, não uma análise de causalidade. Scroll e hover não recebem a mesma exclusão, uma expansão que começa depois dos 500 ms volta a contar e até um movimento não relacionado pode ser excluído se cair dentro da janela. O guia atual do web.dev sobre CLS detalha esse critério.

O ponto difícil está nos movimentos que surpreendem:

  • imagem ocupa espaço só depois do download;
  • banner aparece acima do título;
  • fonte muda a quebra de linha;
  • embed cresce quando inicializa;
  • mensagem de erro empurra o botão;
  • anúncio ou recomendação entra tarde;
  • componente hidratado troca o markup inicial;
  • animação altera largura, altura ou posição.

Meça além do carregamento inicial

Ferramentas de laboratório capturam bem os shifts que acontecem durante a abertura. Elas podem perder mudanças tardias após scroll, consentimento, validação ou navegação em uma página mantida aberta.

Combine:

  • PageSpeed Insights para dados de campo e laboratório;
  • relatório de Core Web Vitals no Search Console quando houver tráfego;
  • painel Performance do Chrome DevTools para reproduzir localmente;
  • biblioteca web-vitals quando o produto precisa relacionar a métrica a uma versão ou rota.

A faixa boa de CLS é até 0,1 no 75º percentil de visitas, separada entre mobile e desktop. O guia de Core Web Vitals para sites criados por IA mostra como registrar uma linha de base sem confundir laboratório e campo.

Antes de editar, anote:

URL:
versão publicada:
dispositivo e largura:
CLS de campo:
CLS de laboratório:
elemento que se moveu:
conteúdo que causou o movimento:
momento da visita:

Reserve espaço para imagens

O navegador consegue calcular a proporção de uma imagem antes do download quando o HTML informa largura e altura.

<img
src="/assets/case-study.webp"
width="1200"
height="800"
alt="Painel com o resultado do projeto"
loading="lazy"
/>

O CSS pode manter a imagem fluida:

img {
max-width: 100%;
height: auto;
}

Os atributos não obrigam a renderização em 1200 por 800 pixels. Eles fornecem a proporção intrínseca de 3 por 2. A documentação da MDN sobre aspect ratio explica como a reserva evita o salto causado por mídia que chega depois da primeira pintura.

Para um contêiner cuja mídia varia:

.video-frame {
aspect-ratio: 16 / 9;
overflow: hidden;
background: #111827;
}
.video-frame > iframe {
width: 100%;
height: 100%;
border: 0;
}

Use a proporção do conteúdo real. Uma caixa 16 por 9 que recebe um vídeo vertical evita o shift, mas cria corte ou espaço vazio.

O artigo sobre otimização de imagens cobre formato, srcset, sizes e lazy loading. Estabilidade depende também de reservar a geometria correta.

Trate imagens responsivas como uma família

Todas as opções de um srcset devem representar o mesmo enquadramento ou declarar a proporção adequada para cada condição.

<picture>
<source media="(max-width: 640px)" srcset="/assets/hero-mobile.avif" width="720" height="900" />
<img
src="/assets/hero-desktop.avif"
width="1440"
height="810"
alt="Produto em uso durante uma reunião"
fetchpriority="high"
/>
</picture>

Confirme o comportamento nos navegadores suportados e teste a largura em que a fonte muda. Se a arte mobile e desktop têm proporções diferentes, a área reservada também precisa acompanhar a seleção.

Não aplique loading="lazy" à imagem de LCP. Isso atrasa a descoberta, embora não seja por si só uma correção de CLS. O guia de priorização de recursos separa tempo de descoberta, prioridade e tamanho.

Dê dimensões a vídeos e embeds

Iframes de vídeo, mapas, calendários e formulários externos costumam iniciar com altura pequena e crescer depois que o script remoto carrega.

Escolha uma destas estratégias:

  • reserve uma proporção fixa;
  • use uma altura mínima compatível com o estado final;
  • mostre um placeholder com as mesmas dimensões;
  • carregue o embed após ação do visitante sem mover conteúdo vizinho;
  • abra a experiência externa em uma nova rota quando ela não cabe na landing.

Um placeholder só funciona quando ocupa o espaço final. Um esqueleto de 200 px substituído por um calendário de 700 px ainda empurra a página.

Evite inserir banners acima do conteúdo

Banners de cookies, campanhas e avisos podem deslocar toda a primeira dobra quando entram no fluxo depois da pintura.

Opções mais previsíveis:

  • reservar a altura desde o HTML inicial;
  • fixar o aviso sem cobrir controles essenciais;
  • renderizar o estado de consentimento no primeiro markup;
  • inserir conteúdo novo abaixo do ponto de leitura atual.

Se usar posição fixa, teste zoom, teclado virtual, safe areas e leitores de tela. Tirar o banner do fluxo não permite esconder conteúdo ou bloquear o botão de recusa.

Controle a troca de fontes

Uma fonte de fallback e a fonte final podem ter métricas diferentes. O título quebra em outra linha, aumenta a seção hero e move tudo abaixo.

Revise:

  • pesos realmente usados;
  • subconjuntos de caracteres;
  • origem e tempo de download;
  • font-display escolhido;
  • fallback com proporções semelhantes;
  • size-adjust, ascent-override, descent-override e line-gap-override quando houver medição para configurá-los.

Não copie valores de outro projeto. Métricas erradas podem cortar texto ou criar outra mudança. O guia de fontes web em sites criados por IA mostra como inventariar famílias e pesos antes de alterar o carregamento.

Reserve os estados do formulário

Mensagens de validação e sucesso aparecem após interação. Mesmo quando o shift fica fora do cálculo de CLS por estar ligado ao clique, o movimento pode atrapalhar a próxima ação.

.field-message {
min-height: 1.5em;
}

Use a área reservada para uma mensagem curta. Erros longos devem quebrar linha sem sobrepor outros campos. Para um alerta global, posicione-o onde a expansão não mova o botão que a pessoa está usando.

O artigo sobre teste de formulários ajuda a percorrer estados vazios, inválidos, carregando, sucesso e falha.

Anime sem recalcular o layout

Transições de top, left, width e height alteram geometria. Quando a intenção é mover ou redimensionar visualmente sem reorganizar os vizinhos, prefira transform.

.card {
transition:
transform 180ms ease,
opacity 180ms ease;
}
.card[inert] {
transform: translateY(8px);
opacity: 0;
pointer-events: none;
}

Use o atributo booleano inert enquanto o card estiver oculto e remova-o na mesma transição que revela o conteúdo. Ele retira o card e seus descendentes da navegação por foco, dos eventos de interação e da árvore de acessibilidade. aria-hidden="true" sozinho não impede que um link ou botão transparente receba foco ou clique. Se o foco já estiver dentro do card, mova-o para um controle visível antes de ativar inert.

Nem todo movimento deve ser convertido mecanicamente. Um acordeão precisa abrir espaço para o conteúdo e continua sendo uma alteração de layout esperada. Preserve foco, leitura e prefers-reduced-motion.

Cuidado com conteúdo fora da viewport

content-visibility: auto pode evitar parte do trabalho de renderização de seções distantes. Para manter a rolagem estável, combine a propriedade com uma estimativa de tamanho:

.below-fold-section {
content-visibility: auto;
contain-intrinsic-size: auto 720px;
}

A estimativa ruim pode produzir mudança na barra de rolagem quando o conteúdo real for renderizado. Use a propriedade depois de medir se layout e pintura fora da tela são um custo relevante. Não aplique em conteúdo da primeira dobra.

Encontre a causa do movimento

O elemento destacado pelo DevTools é o que se moveu. A causa pode estar acima dele.

Se o botão desceu, procure:

  • imagem anterior sem dimensões;
  • fonte que alterou o título;
  • banner inserido no topo;
  • componente que trocou altura;
  • CSS carregado tarde;
  • markup de servidor diferente do estado hidratado.

Corrigir o botão com position: absolute pode apenas esconder o sintoma e criar sobreposição. Preserve o fluxo quando ele representa a estrutura da página.

Valide em estados reais

Repita a visita em:

  • mobile e desktop;
  • cache vazio e quente;
  • conexão lenta;
  • fonte carregada e bloqueada;
  • consentimento novo e já salvo;
  • formulário com erro e sucesso;
  • embed disponível e indisponível;
  • scroll até o fim;
  • navegação de volta pelo histórico;
  • URL padrão e domínio próprio.

Uma gravação de laboratório sem interação não cobre essa lista. Se os dados de campo apontam CLS e o laboratório não reproduz, adicione medição por versão antes de tentar correções amplas.

Republique sem trocar o endereço

Depois da correção:

  1. rode build e checks do projeto;
  2. abra o resultado local sem iniciar um servidor quando o artefato permitir inspeção direta;
  3. confirme dimensões, rotas e assets do pacote;
  4. aplique a mudança pelas file tools e publique pelo fluxo de Publicação;
  5. preserve o Site ID e o slug;
  6. abra a URL final e percorra os estados que causavam o movimento;
  7. compare laboratório e dados de campo quando a nova versão acumular visitas.

Se o HTML novo referencia imagens com hash, confirme que os novos assets existem em public/ e remova explicitamente os que ficaram obsoletos. O guia para evitar assets antigos após republicar mostra como impedir a mistura entre HTML e mídia de versões diferentes.

Prompt para uma revisão focada

Revise os layout shifts desta landing page sem publicar ainda.
URL e versão: [URL e commit]
Dispositivo e largura: [contexto]
Evidência: [CLS de campo, laboratório ou trace]
Estado que dispara o movimento: [passos]
1. Identifique o elemento que se move e o conteúdo que causou o movimento.
2. Separe mídia, fonte, conteúdo assíncrono, hidratação e animação.
3. Reserve espaço com dimensões compatíveis com o estado final.
4. Preserve design, responsividade, acessibilidade e conversão.
5. Faça uma mudança pequena e rode os checks do projeto.
6. Mostre como repetir a medição antes de republicar.

Uma landing estável não precisa parecer imóvel. Ela precisa respeitar o espaço que prometeu. Imagens, fontes e integrações podem chegar depois sem arrancar o controle debaixo do dedo de quem já começou a usar a página.