Forced reflow no Lighthouse: o que significa e como corrigir
Um script que altera a página e pede um tamanho logo depois faz o navegador refazer o layout na mesma hora. Quando isso faz os toques travarem e quando é inofensivo.
O que significa Forced reflow no Lighthouse?
Um forced reflow significa que um script alterou a página e pediu um tamanho logo depois, obrigando o navegador a recalcular o layout na mesma hora. O Lighthouse lista esses scripts no insight Forced reflow ("A forced reflow occurs when JavaScript queries geometric properties"). Acontecer uma vez é normal; em um loop, faz os toques travarem. Deixe o CSS fazer o trabalho do script ou leia todos os tamanhos antes de alterar qualquer coisa.
Table of Contents!
O que o aviso de Forced reflow lista?
O Lighthouse 13 e o PageSpeed Insights descrevem isso assim: "A forced reflow occurs when JavaScript queries geometric properties (such as offsetWidth) after styles have been invalidated by a change to the DOM state. This can result in poor performance. Learn more about forced reflows and possible mitigations." O aviso fica vermelho quando scripts forçam 30 ms ou mais de trabalho de layout de uma só vez durante o carregamento da página.
O relatório abaixo vem de uma página de listagem de chalés que criei como um site de aluguel por temporada em WordPress, onde o script do tema corta cada descrição para três linhas e deixa todos os cards com a mesma altura.

Lighthouse 13.5 no celular, throttling do DevTools (Slow 4G, 4x CPU).
- Top function call: a função externa que iniciou o trabalho de layout. Passe o cursor sobre o caminho encurtado do arquivo para ver o caminho completo, que identifica o tema, plugin ou app. Um arquivo em outro domínio geralmente é uma tag de terceiros, como um gravador de sessão (Scripts que você não pode alterar).
- Source: cada linha de código que pediu um tamanho.
- Total reflow time: o tempo de layout causado por essa função ou linha.
- Unscored: o insight não tem peso na pontuação de Performance. As long tasks por trás dele (intervalos acima de 50 ms nos quais a página não consegue responder) reduzem a pontuação pelo Total Blocking Time.
A linha superior (388 ms) é menor que a soma das linhas de Source (743 ms) porque o script dos chalés executa duas vezes durante o carregamento, e a linha superior mostra apenas a maior execução.
Por que um script força o navegador a refazer o layout?
Na listagem de chalés acima, um toque no filtro "All" congela a página por um terço de segundo antes de os 48 cards aparecerem.
O layout é a etapa em que o navegador calcula onde cada caixa fica e qual é o seu tamanho. Ele normalmente faz isso uma vez por frame, depois que os scripts são executados. Quando um script altera a página (um texto, uma classe, uma altura) e depois lê um tamanho, como offsetHeight, getBoundingClientRect(), scrollTop ou getComputedStyle(), o navegador precisa fazer o layout na hora, dentro do script, para responder. O Paul Irish mantém a lista completa das leituras que forçam isso.
Um único forced reflow é, na maior parte, trabalho de layout que o navegador faria um instante depois. Em um loop que altera e lê de novo, acontece um layout completo a cada iteração: layout thrashing. O tema dos chalés corta cada descrição assim:
while (el.offsetHeight > max && words.length > 1) {
words.pop();
el.textContent = words.join(' ') + '…';
} Cada palavra removida altera o texto, então a leitura seguinte de offsetHeight força um novo layout: um por palavra, em cada card.
Quanto um forced reflow deixa a página mais lenta?
Medi a listagem de chalés com o script do tema (Antes) e com CSS cortando o texto e igualando a altura dos cards (Depois). As duas versões têm a mesma aparência.
| Antes | Depois | |
|---|---|---|
| Pontuação no Lighthouse | 84 | 92 |
| Total Blocking Time | 360 ms | 0 ms |
| Total reflow time | 743 ms | nenhum |
| Um toque em "All" | 320 ms | 16 ms |

Antes

Depois
Lighthouse 13.5 no celular, throttling do DevTools.
Os 8 pontos vêm do Total Blocking Time: os layouts forçados mantêm a página bloqueada por mais tempo. O toque é o que o visitante percebe, e conta para o INP (Interaction to Next Paint), o Core Web Vital que mede a rapidez com que a página responde a toques e cliques. 320 ms fica acima do limite de 200 ms para um bom INP, e 298 ms disso foi trabalho de layout forçado pelo script; 16 ms equivale a um único frame. O Lighthouse nunca toca na tela, então medi os toques no Chrome com a CPU desacelerada para a velocidade de um celular.
Quando um forced reflow é inofensivo?
- Uma linha pequena durante o carregamento. Uma linha pouco acima de 30 ms costuma ser o primeiro layout da página, adiantado um pouco porque um script pediu um tamanho. O script de tema da listagem de chalés, reescrito para ler todas as alturas primeiro, mostrou uma linha de 37 ms em uma de quatro execuções do Lighthouse, e o toque em "All" levou 16 ms.
- Uma linha "[unattributed]". Ela não indica nenhuma linha de código: execute o Lighthouse novamente e, se a linha sumir, deixe como está.
- Um script que inicia uma animação. Modais do Bootstrap e alguns plugins de popup leem um tamanho de propósito para que a transição CSS deles comece.

Lighthouse 13.5 no celular, throttling do DevTools.
Corrija quando o total reflow time estiver na casa das centenas de milissegundos, quando um mesmo arquivo tiver várias linhas ou quando o script também rodar em toques: um filtro, um menu, um slider.
Qual script causa o forced reflow em um toque?
O Lighthouse apenas carrega a página, então grave no painel Performance os toques que travam:
- Abra o DevTools (F12), vá em Performance e ajuste a CPU para 4x slowdown, para que seu notebook se comporte como um celular.
- Clique em Record, toque no que parece lento e pare a gravação.
- Abra Forced reflow na barra lateral Insights. "Call frames that trigger reflow" indica a função e a linha.

Um toque em "All" na listagem de chalés: clampText em cabins.js.
O console relata a mesma coisa como "[Violation] Forced reflow while executing JavaScript took 38ms", assim que você ativa Verbose nos níveis de log.
Quando o Lighthouse cita apenas jquery.min.js, o jQuery fez a leitura no lugar de um tema ou plugin. Grave um recarregamento no painel Performance e clique em um bloco de Layout com triângulo vermelho: sob Function stack no Summary, o arquivo entre as linhas do jQuery, com um caminho como /wp-content/plugins/<name>/, é o plugin.
Os field data registram os toques e cliques dos visitantes reais. No CoreDash, abra INP, Breakdown e agrupe por LOAF: o Chrome registra quais scripts rodaram em cada frame lento (Long Animation Frames), então cada linha é um script com o INP das interações em que ele executou. Um forced reflow em um handler de clique ou toque conta como processing, a parte roxa de cada barra, então comece por um script lento cuja parte roxa seja longa.

INP por script no CoreDash, desktop, p75: verde é input delay, roxo processing, azul presentation.
Como corrigir um forced reflow?
Comece pelo arquivo indicado em Top function call e veja se o CSS pode fazer o trabalho do script. Texto cortado em três linhas (line-clamp), cards com a mesma altura (grid), cabeçalho fixo no topo (position: sticky) e caixa de imagem que mantém as proporções (aspect-ratio) não precisam de script. Sem o script, nada força o layout.
Depois de aplicar qualquer correção abaixo, grave o mesmo toque de novo: Forced reflow deve ter sumido da barra lateral Insights. Em seguida, verifique no Lighthouse e nos field data; o Search Console leva até 28 dias.
Temas, plugins e page builders do WordPress
O caminho em Top function call indica o tema (/wp-content/themes/) ou o plugin (/wp-content/plugins/). Procure primeiro por uma configuração. A opção "Stretch Section" do Elementor alarga uma seção com JavaScript a cada carregamento e resize; o layout de página Elementor Full Width com um container de largura total faz isso com CSS. Um slider Swiper configurado com "auto" em slides per view mede cada slide; com um número fixo, ele calcula as larguras sem precisar lê-las.
Adiar o JavaScript no WP Rocket ou em um plugin parecido elimina o aviso, mas o script passa a rodar no primeiro toque ou scroll do visitante, com os mesmos layouts forçados. Em vez disso, corrija o script ou relate o problema ao desenvolvedor do plugin e troque de plugin se nada mudar.
Quando o tema cortar texto com JavaScript, corte com CSS no child theme, usando a classe de texto do tema:
.cabin .desc {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
line-clamp: 3;
overflow: hidden;
} Depois, desative o script de clamp do tema: por uma opção do tema ou com wp_dequeue_script() usando o handle dele.
Temas e apps da Shopify
No editor de temas, em App embeds, desative os apps um por um e execute o Lighthouse novamente. Quando o aviso sumir, relate o problema ao desenvolvedor desse app ou substitua o app. Um caminho com /assets/ em Top function call é um arquivo do tema, seja do próprio tema ou de um app que inseriu código nele. O Dawn e os temas baseados nele costumam ler o tamanho uma única vez e agrupar as alterações em lote; portanto, olhe os apps primeiro.
JavaScript próprio e React
Quando um script precisa medir, leia todos os tamanhos primeiro e faça as alterações depois, para que um único layout atenda a todas as leituras. Veja um accordion que ajusta cada painel à sua própria altura:
const panels = [...document.querySelectorAll('.panel')];
// A layout for every panel: read, write, read, write
panels.forEach(p => { p.style.maxHeight = p.scrollHeight + 'px'; });
// One layout: read every height, then write them all
const heights = panels.map(p => p.scrollHeight);
panels.forEach((p, i) => { p.style.maxHeight = heights[i] + 'px'; }); - Resize e scroll: ResizeObserver e IntersectionObserver entregam os tamanhos a partir do layout que o navegador acabou de fazer. Use-os em vez de ler tamanhos em um handler de resize ou scroll.
- React: meça uma única vez no
useLayoutEffecte atualize o estado uma só vez. Monte menus, popovers e tooltips quando eles abrirem, para que os elementos fechados não meçam nada durante o carregamento.
Scripts que você não pode alterar
Gravadores de sessão e tags de mapa de calor leem tamanhos de propósito: o Microsoft Clarity lê uma dúzia de tamanhos de página ao iniciar e a posição de tudo o que um visitante clica. Remova a tag, grave uma amostragem das visitas ou carregue o script apenas nas páginas que você estiver analisando.
Forced reflow em um plugin ou app que você não consegue substituir, ou toques que travam no celular dos visitantes e não no seu? Em uma Core Web Vitals power hour, encontramos o script por trás dos toques mais lentos e decidimos juntos se o caminho é corrigir, substituir ou remover.
Search Console reclamou do seu site?
Entrego uma lista priorizada de fixes baseada em dados de campo. Não um PDF de 50 páginas.
Solicitar auditoria