Encontrar e corrigir problemas de Cumulative Layout Shift (CLS)
Saiba como encontrar e corrigir todos os problemas de Cumulative Layout Shift com dados de RUM, Chrome DevTools e fixes específicos de CSS e HTML
Partilhar
Encontrar e corrigir problemas de Cumulative Layout Shift (CLS)
Esta página faz parte da nossa série sobre Cumulative Layout Shift (CLS). O CLS mede a estabilidade visual da página ao registar o movimento inesperado de conteúdos. Um bom valor de CLS fica abaixo de 0,1; valores acima de 0,25 são fracos. Se ainda não domina o CLS, comece pela página principal de CLS para consultar a fórmula, os limites e o funcionamento das session windows.
O CLS é a Core Web Vital com melhor desempenho. Segundo o Web Almanac de 2025, 72% dos websites passam no CLS a nível global. Parece ótimo até perceber que a maioria dos programadores nunca vê problemas de CLS na sua própria máquina. Os desvios acontecem com novos visitantes em ligações lentas. Quando vai verificar nas DevTools com a cache quente, tudo parece bem. É exatamente isso que torna o CLS difícil de depurar.
Este guia baseia-se no processo passo a passo exato que utilizo na minha consultoria de CLS. Primeiro dados do CrUX e de RUM, validar no Chrome e só depois escrever o fix.
Revisto pela última vez por Arjen Karel em março de 2026
DICA DE CLS: O CLS é medido em session windows e não como um total acumulado. O browser agrupa os layout shifts em sessões (máximo de 5 segundos, intervalos de 1 segundo entre desvios) e a pontuação de CLS corresponde à pior sessão. Um único pico de desvios durante o carregamento da página pode fazer o CLS falhar, mesmo que o resto da visita seja perfeitamente estável.
Passo 1: Verificar o CLS no Search Console
Antes de alterar o que quer que seja, confirme se tem realmente um problema de CLS. Aceda ao Google Search Console, vá a Core Web Vitals e verifique tanto em telemóvel como em desktop.
Se o Google estiver a assinalar URLs com «Problema de CLS: mais de 0,25» ou «Problema de CLS: mais de 0,1», tem a confirmação do Chrome User Experience Report (CrUX) de que utilizadores reais estão a sofrer layout shifts no site.
Ao contrário do LCP e do INP, onde o poder de processamento e a velocidade de rede são determinantes, os problemas de CLS podem ser específicos do dispositivo ou do tamanho do ecrã. Quando um problema semelhante afeta o telemóvel e o desktop (imagens sem dimensões, trocas de fontes, conteúdo injetado), o desktop pode reportar um valor de CLS muito mais elevado devido ao tamanho do ecrã (uma vez que uma área maior do viewport visível pode ser afetada). O Search Console agrupa URLs, por isso diz-lhe que tipos de página são afetados, mas não quais os elementos que se estão a mover. Para isso, precisa de Real User Monitoring.

Passo 2: Identificar problemas de CLS com dados de RUM
O Search Console confirma a existência do problema, mas quase não dá pistas para trabalhar. Precisa de descobrir que elementos estão a mexer-se, em que páginas e sob que condições. Para isso, precisa de uma ferramenta de RUM.
Criei o CoreDash exatamente para responder a estas perguntas. Adiciona uma tag de script e a ferramenta começa a recolher dados de atribuição de CLS de cada visitante real. O dado fundamental para o debug de CLS é o elemento em desvio: o nó do DOM que realmente se moveu. Sem essa informação, está a fazer debug às cegas.
Encontrar elementos em desvio
Comece por analisar os dados de CLS agrupados por elemento. No CoreDash, aceda à página de CLS e veja a tabela de dados ordenada por «CLS by Element». Isto mostra que elementos causam mais layout shift em todos os visitantes. Clique no pior para filtrar todas as métricas para as páginas onde esse elemento se moveu.

Identificar as páginas afetadas
Depois de filtrar pelo elemento em desvio com maior impacto, analise o detalhe por URL. Os problemas de CLS podem afetar todo o site ou modelos específicos. Agora já sabemos se o CLS está concentrado em tipos de página específicos: páginas de produto com galerias de imagens, artigos de blog com blocos de anúncios ou landing pages com animações na secção hero. Saber que páginas falham indica-lhe onde se focar.
Comparar novos visitantes com visitantes recorrentes
Esta é outra verificação rápida que faço e tem muito mais importância do que a maioria pensa. O CLS por troca de fontes só acontece quando a fonte não está em cache. O CLS de imagens devido a width: auto só acontece quando a imagem não está na cache do browser. Se o CLS for muito pior para novos visitantes, está perante um desvio dependente da cache que você, como programador, nunca verá na sua máquina a menos que desative a cache (dica: desative sempre a cache do Chrome... mas isso fica para outro dia).
Verificar tipos de dispositivo e tamanhos de viewport
O CLS mostra tipicamente um padrão mobile/desktop diferente do LCP e do INP. Os layouts responsivos podem introduzir desvios que só surgem em larguras e alturas de viewport específicas. Um bloco de anúncios problemático em desktop pode nem estar no viewport em telemóvel. Um menu de navegação pode animar de forma diferente em breakpoints menores. Agrupe os dados de CLS por tipo de dispositivo para saber onde ocorrem.
Passo 3: Fazer debug do CLS com o Chrome
Os dados de RUM já indicaram que elementos sofrem desvios e porquê. Agora, reproduza o problema localmente e descubra o que o está a causar.
Utilizar o Core Web Vitals Visualizer
A forma mais rápida de ver layout shifts é com a extensão de Chrome Core Web Vitals Visualizer. Carregue a página, clique no ícone da extensão e recarregue. Cada layout shift é destacado com uma sobreposição colorida que mostra exatamente o que se moveu e quanto. Utilizo isto como primeiro passo antes de abrir o painel Performance, porque dá uma resposta visual imediata.

Replicar as condições no Chrome e verificar os screenshots de rede
Os problemas de CLS são muitas vezes invisíveis com a cache quente. Abra as DevTools, desative a cache no separador Network e limite a ligação para «Slow 4G» (a minha opção favorita; mostra o CLS provocado por race conditions). Agora clique no ícone de roda dentada e desative a cache (com as DevTools abertas). Isto simula as condições que os novos visitantes experienciam. Vá ao separador Network e ative os screenshots. Agora recarregue a página e fique atento aos desvios.

Utilizar o painel Performance do Chrome
A maioria dos layout shifts é fácil de identificar quando se sabe como procurar, mas alguns teimam em escapar. É nessa altura que deve abrir as DevTools do Chrome (Ctrl+Shift+I) e ir ao painel Performance para uma análise detalhada. Prima Ctrl+Shift+E para recarregar e gravar. Depois de a página carregar, faça scroll para cima e para baixo algumas vezes. Pare a gravação.
Procure a faixa «Layout Shifts». Cada desvio aparece como um bloco colorido. Clique num desvio para ver:
- O nó em desvio: o elemento do DOM que se moveu
- A pontuação do desvio: impact fraction multiplicada pela distance fraction
- hadRecentInput: se uma ação do utilizador antecedeu o desvio (cliques e toques têm uma tolerância de 500 ms, mas o scroll não)
Preste atenção ao momento em que os desvios acontecem. Desvios durante o carregamento da página apontam para imagens sem dimensões, trocas de fontes ou transições de CSS. Desvios durante o scroll apontam para animações ativadas por scroll que utilizam propriedades de layout.

Teste rápido: desativar todas as transições
As transições de CSS que animam propriedades de layout são uma causa traiçoeira de CLS, porque só provocam desvios durante a fase de carregamento e são difíceis de reproduzir. Cole este snippet na consola, force o recarregamento da página com a cache desativada e compare o CLS:
document.head.insertAdjacentHTML('beforeend',
'<style>*{transition-property:none!important}</style>'); Se o CLS descer depois de desativar as transições, encontrou a causa. Utilize o guia de depuração de transições de CSS para encontrar as transições específicas responsáveis.
Medir o CLS com a Layout Instability API
A Layout Instability API dá acesso direto a cada layout shift em JavaScript. É a mesma API que as ferramentas de RUM utilizam nos bastidores:
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (!entry.hadRecentInput) {
console.log('Layout shift:', {
value: entry.value,
sources: entry.sources?.map(s => ({
node: s.node,
previousRect: s.previousRect,
currentRect: s.currentRect
}))
});
}
}
});
observer.observe({ type: 'layout-shift', buffered: true }); O array sources mostra que elementos se moveram. O hadRecentInput filtra os desvios esperados decorrentes de cliques e toques. Para medição em produção, utilize o CoreDash ou outra ferramenta de RUM.
Passo 4: Corrigir problemas de CLS
Já sabe que elementos se movem e porquê. É altura de os corrigir. O CLS não tem fases sequenciais como o LCP. Em vez disso, os layout shifts dividem-se em categorias de causas distintas. Eis as mais comuns, pela ordem em que as encontro nas auditorias.
1. Imagens, vídeos e iframes sem dimensões
Esta é a causa número um de CLS na web. O Web Almanac de 2025 indica que 62% das páginas em dispositivos móveis têm pelo menos uma imagem sem dimensões. A solução: inclua sempre os atributos width e height nas tags <img>, <video> e <iframe>.
<img src="hero.jpg" width="800" height="450" alt="Description">
<style>
img {
height: auto;
max-width: 100%;
}
</style> Cuidado com o width: auto no CSS. Esta única declaração anula o cálculo da proporção feito pelo browser e provoca layout shifts mesmo que tenha definido a largura e a altura no HTML. Já vi isto em dezenas de sites. O programador fez tudo bem no markup, mas uma regra global de CSS como img { width: auto; height: auto; max-width: 100%; } deitou tudo a perder. Para a explicação completa, consulte como corrigir layout shifts causados por imagens com dimensionamento automático. Para um guia completo que cobre todas as causas de CLS em imagens e media (vídeos, iframes, art direction, imagens responsivas, lazy loading, placeholders), consulte Como as imagens e os media causam layout shift.
2. Trocas de web fonts
Quando uma web font carrega e substitui a fonte de fallback, a diferença de dimensões provoca um layout shift. O Web Almanac de 2025 mostra que apenas 11% das páginas fazem preload de web fonts. Isso significa que a grande maioria dos sites está vulnerável a CLS por troca de fontes.
A correção divide-se em duas partes. Primeiro, faça com que a fonte de fallback coincida com as dimensões da web font através de metric overrides:
<style>
@font-face {
font-family: 'My Font Fallback';
src: local('Arial');
size-adjust: 105.2%;
ascent-override: 93%;
descent-override: 24%;
line-gap-override: 0%;
}
@font-face {
font-family: 'My Font';
src: url('/fonts/myfont.woff2') format('woff2');
font-display: swap;
}
body {
font-family: 'My Font', 'My Font Fallback', sans-serif;
}
</style> Utilize um Fallback Font Generator para calcular os valores de override corretos para a combinação de fontes. Em segundo lugar, acelere a entrega: aloje as suas próprias fontes, faça preload do ficheiro de fonte crítico e utilize WOFF2 com subsetting. Para uma estratégia completa, consulte carregamento responsivo de web fonts e garantir que o texto permanece visível durante o carregamento de web fonts.
3. Animações e transições de CSS
De acordo com o Web Almanac de 2025, 40% das páginas em dispositivos móveis executam animações não compostas (non-composited). Estas animam propriedades como width, height, top, left, margin e padding, que despoletam recalculações de layout em cada frame.
O problema mais comum é o transition: all. Quando um programador escreve transition: all .3s ease, qualquer alteração de propriedade é animada, incluindo propriedades de layout. Durante o carregamento da página, os elementos que transitam do seu estado não formatado para o formatado produzem layout shifts intermitentes e quase impossíveis de reproduzir de forma consistente. Vejo este padrão constantemente.
A solução: substitua propriedades que acionam o layout por propriedades compostas.
- Utilize
transform: translateY()em vez detop/bottom - Utilize
transform: translateX()em vez deleft/right - Utilize
transform: scale()em vez dewidth/height - Utilize
opacityem vez devisibilitycombinada com alterações de altura - Nunca utilize
transition: all. Especifique a propriedade exata:transition: background-color .2s ease
O transform e o opacity correm inteiramente na thread do compositor e nunca acionam o layout. Para o processo completo de debug, consulte layout shifts causados por transições de CSS.
4. Anúncios, embeds e conteúdo injetado dinamicamente
Os anúncios carregam tarde e empurram o conteúdo para baixo. Os banners de consentimento de cookies surgem e desviam a página. Os pedidos AJAX injetam novos conteúdos sem reservar espaço previamente. Tudo isto é o mesmo problema: surge algo na página que o browser desconhecia no momento da renderização.
A solução para todos estes casos é reservar espaço. Nos blocos de anúncios, defina um min-height que corresponda ao tamanho previsto do anúncio:
<style>
.ad-slot {
min-height: 250px;
contain: layout style;
}
@media (min-width: 600px) {
.ad-slot { min-height: 90px; }
}
</style> A declaração contain: layout style isola o contentor do anúncio do resto da página. Nos banners de cookies, utilize position: fixed para criar uma sobreposição em vez de empurrar o conteúdo. No conteúdo de AJAX, reserve espaço com min-height. Não precisa de acertar à risca: uma diferença de 50px causa muito menos CLS do que um desvio de 400px sem qualquer reserva de espaço.
Para embeds de terceiros como o YouTube, o Google Maps e widgets de chat, utilize o padrão de fachada (facade pattern): apresente um placeholder estático e carregue o embed real apenas quando o utilizador interagir com ele. Zero CLS, zero recursos desperdiçados.
5. Layout shifts provocados pelo scroll
Esta é a causa de CLS que o Lighthouse nunca deteta. O Lighthouse não faz scroll na página, pelo que os layout shifts acionados por scroll são completamente invisíveis em testes de laboratório. A única forma de os encontrar é com dados de RUM ou gravando um trace no painel Performance enquanto faz scroll manual.
O exemplo mais comum é um cabeçalho que se esconde ao fazer scroll e anima a propriedade top. Eis o que a maioria dos programadores não sabe: o scroll não é uma interação excluída na especificação da Layout Instability. Os cliques e toques têm uma tolerância de 500 ms. O scroll não. Qualquer layout shift provocado pelo scroll conta para a pontuação de CLS.
A solução: utilize transform: translateY() em vez de top para qualquer animação acionada por scroll. O mesmo aplica-se a efeitos de parallax, barras de navegação que encolhem e barras de progresso associadas ao scroll. Se se mexe no scroll, anime com transform. Para o passo a passo completo com exemplos em vídeo, veja como as animações acionadas por scroll causam CLS.
Checklist de correções rápidas
| Causa de CLS | Como detetar | Correção |
|---|---|---|
| Imagens/vídeos sem dimensões | Auditoria de «unsized images» do Lighthouse | Adicionar width e height; remover width: auto do CSS |
| Trocas de web fonts | RUM: CLS pior apenas na primeira visita | Font metric overrides; preload de WOFF2; fazer self-host de fontes |
| Transições de CSS | Snippet de consola para listar todas as transições | Substituir transition: all por propriedades específicas; utilizar transform/opacity |
| Anúncios de carregamento tardio | Atribuição de RUM a mostrar elementos de contentor de anúncios | min-height nos blocos de anúncios; contain: layout style |
| Banners de consentimento de cookies | Pico de CLS na primeira visita; banner nos dados de atribuição | Utilizar sobreposição com position: fixed em vez de empurrar conteúdo |
| Animações de scroll | Trace de Performance durante o scroll; CLS de field data > CLS de lab data | Substituir top/left/height por transform |
Guias relacionados
- Como as imagens e os media causam layout shift: o guia completo sobre CLS provocado por imagens sem dimensões, vídeos, iframes, art direction, imagens responsivas, lazy loading e placeholders.
- Corrigir layout shifts causados por imagens com dimensionamento automático
- Layout shifts causados por transições de CSS
- Animações acionadas por scroll e o CLS
- Garantir que o texto permanece visível durante o carregamento de web fonts
- Fazer self-host de Google Fonts
- Carregamento responsivo de web fonts
Para uma visão geral completa de todas as Core Web Vitals, visite o hub de Core Web Vitals ou utilize a Checklist definitiva de Core Web Vitals para auditar todo o site.

Precisa de um site mais rápido?
Sou o Arjen e há 17 anos que corrijo sites lentos. Se tem problemas que não consegue resolver sozinho, envie-me o seu URL e falamos.
Envie-me o seu URL
Porque é que o nosso fix não está a funcionar?
Por vezes a CDN ainda serve o HTML antigo, ou o fix foi feito no template de desktop e o mobile usa outro. Envie-me o seu URL e o problema, e respondo com alguns horários. Primeiro analiso os seus field data, depois dedicamos uma hora ao seu site, e no prazo de um dia tem as minhas notas por escrito. 350 € sem IVA.
Envie-me o seu URLSem programador para fazer o fix? Faço eu o trabalho, numa cópia do seu site.