Render-blocking requests no Lighthouse: como os corrigir
O Lighthouse 13 lista todas as stylesheets e scripts pelos quais a página espera antes do primeiro paint, incluindo os rápidos. Quando isso custa tempo aos visitantes e quais as correções de CSS que funcionam.
Os render-blocking requests prejudicam a pontuação?
O Lighthouse lista todas as stylesheets e scripts pelos quais a página esperou antes do primeiro paint no insight Render-blocking requests ("Requests are blocking the page's initial render, which may delay LCP"), chamado "Eliminate render-blocking resources" antes do Lighthouse 13. O insight não conta para a pontuação, mas enquanto a página espera pelo CSS e pelos scripts fica em branco, o que atrasa o FCP e o LCP, sobretudo num telemóvel. Reduza e combine o CSS e adie os scripts.
Table of Contents!
O que verifica o insight Render-blocking requests?
A descrição do Lighthouse diz: "Requests are blocking the page's initial render, which may delay LCP. Deferring or inlining can move these network requests out of the critical path." Fazer inlining não é a solução: veja abaixo. A tabela tem três colunas: URL, Transfer Size e Duration. O Transfer Size é o ficheiro tal como foi enviado, comprimido. O Duration é a estimativa do Lighthouse para o tempo que o request demora num telemóvel lento, incluindo uma nova ligação a outro domínio.
Ao carregar uma página, o Chrome marca cada request como render-blocking ou não e regista isso no trace. O Lighthouse lê o trace e lista todos os requests no frame principal que o Chrome marcou como bloqueadores e que terminaram antes do primeiro paint. Na prática, são as stylesheets e os scripts síncronos no <head> e os ficheiros que estes carregam com @import. Uma stylesheet no body só conta na prioridade mais alta do Chrome e um script na prioridade alta; após a primeira imagem, ambos descem de prioridade e são ignorados. Não há qualquer tolerância: basta um ficheiro listado para falhar o insight.
Alguns ficheiros nunca aparecem, mesmo quando tornam a página mais lenta: scripts async, ficheiros adicionados à página por um script (gtm.js, gtag.js), estilos e scripts inline, tudo o que esteja num iframe e tipos de letra.

O insight numa página de produto WooCommerce, Lighthouse 13.5.0, throttling simulado como no PageSpeed Insights.
O que torna um ficheiro render-blocking?
Render-blocking significa que o browser não renderiza nada até esse ficheiro chegar: todas as stylesheets no <head> têm de chegar e todos os scripts síncronos aí presentes têm de ser descarregados e executados.
- Um script a seguir a uma stylesheet espera por essa stylesheet. O Chrome não executa um script síncrono até o CSS que está acima chegar, e o parser espera pelo script. Ambos os ficheiros podem ser descarregados em paralelo e, ainda assim, paga pelo CSS e depois pelo script.
- Um
@importcomeça tarde. O preload scanner do Chrome encontra todos os links no HTML de uma só vez, mas um@importdentro de um ficheiro CSS só é descoberto quando esse ficheiro chega. Na página de produto abaixo, a stylesheet importada do tema começou aos 1,28 s, contra 0,59 s quando estava ligada a partir do HTML. - Outro domínio custa uma ligação. Uma stylesheet em fonts.googleapis.com ou numa CDN precisa de DNS, TCP e TLS antes que o seu primeiro byte chegue.
| No Chrome | Bloqueia o primeiro paint? |
|---|---|
<link rel="stylesheet"> no head | Sim |
o mesmo com fetchpriority="low" | Sim |
o mesmo com media="print" | Não, é descarregado na mesma |
rel="preload" mais um link de stylesheet para o mesmo ficheiro | Sim |
@import numa stylesheet bloqueadora | Sim, a seguir à stylesheet que o importa |
<script src> no head | Sim |
async | Não, mas pode executar antes do paint |
defer, type="module" | Não |
| uma stylesheet no body | Apenas o conteúdo abaixo dela |
Os render-blocking requests afetam o FCP e o LCP?
Fiz a medição numa página de produto WooCommerce com nove stylesheets e dois scripts no head, num telemóvel com ligação Slow 4G. Na versão corrigida, o CSS foi reduzido e combinado numa única stylesheet de 6,6 kB e ambos os scripts ficaram com defer. Depois de carregada, a página fica exatamente igual.
FCP
A versão original fez o primeiro paint aos 2,12 s; a versão corrigida, aos 1,39 s.

Antes

Depois
Ambas as versões aos 1,4 s no telemóvel com throttling: a original continua em branco.
LCP
O LCP não pode ocorrer antes do primeiro paint. Aqui, o elemento de LCP é a fotografia do produto, e esta também não pode aparecer antes de o CSS chegar: com a correção, o LCP passou de 2,25 s para 1,91 s. Numa análise detalhada do LCP, essa espera surge como element render delay. O Lighthouse não mostra isto: com uma imagem como elemento de LCP, estima sempre uma poupança de LCP de 0 ms. Não conclua por isso que não há efeito no LCP.
Quantos sites são afetados e é seguro ignorar?
Quase todos. O State of CWV analisa as páginas iniciais de 114 526 sites com dados do CrUX: 92,8% têm pelo menos um render-blocking request, 91,2% uma stylesheet bloqueadora e 62,5% um script bloqueador. Nos que os têm, a mediana é de 8 requests e 110 kB, e um em cada cinco sites tem mais de 20. (O State of CWV contabiliza stylesheets e scripts síncronos no head, o que se aproxima muito da lista do Lighthouse.)
Sites com muitos requests destes têm pior desempenho no terreno. 84,0% dos sites sem nenhum têm um bom FCP em telemóveis, contra 54,1% dos sites com mais de 20. Mas o servidor explica a maior parte dessa descida: no mesmo intervalo, a mediana do TTFB duplica, de 538 ms para 1114 ms. Dividido pela velocidade do servidor:

Sites com um bom FCP em telemóveis por número de render-blocking requests e tempo de resposta do servidor. State of CWV, outubro de 2026, CrUX p75 em telemóveis, um bom FCP é de 1,8 s ou menos.
- Servidor rápido (TTFB abaixo de 600 ms): 94 a 97% têm um bom FCP, qualquer que seja o número. Esse tempo continua a existir: do primeiro byte ao primeiro paint demora cerca de mais 150 a 200 ms com 21 ou mais requests bloqueadores do que sem nenhum.
- Servidor lento (TTFB de 900 ms ou mais): a percentagem de bom FCP cai de cerca de metade dos sites (47 a 53%) com até dois requests bloqueadores para 30% com 21 ou mais. Com um TTFB de 900 ms ou mais, sobram menos de 0,9 s antes do limite de 1,8 s para um bom FCP, pelo que cada request extra pelo qual o paint espera pode empurrar o FCP para além do limite.
Os sites em WordPress têm ainda mais: 57% têm 16 ou mais requests bloqueadores (mediana de 19, 163 kB). Para a mesma velocidade de servidor, isso custa 3 pontos percentuais de bom FCP em comparação com um a cinco requests num host rápido, e cerca de 10 pontos num lento.
Isto é uma correlação, mas estabelece a ordem de prioridades: com um TTFB lento, resolva primeiro o servidor. Num servidor rápido, poupar esses 150 a 200 ms continua a valer a pena se o CSS for seu. Pode ignorar o aviso quando:
- o Lighthouse lista apenas uma ou duas pequenas stylesheets próprias, cada uma abaixo de cerca de 15 kB;
- o ficheiro listado é uma ferramenta de consentimento, um snippet de testes A/B ou um ficheiro da plataforma que não pode alterar (veja abaixo).
Como detetar render-blocking requests no field data?
O Lighthouse carrega a página uma vez, a frio. Após a primeira página, os visitantes já têm o CSS na cache; por isso, no field data o custo reflete-se sobretudo na primeira página que um visitante carrega. No CoreDash, analise dois pontos em mobile:
- FCP ao lado do TTFB. Os ficheiros render-blocking gastam o seu tempo entre o primeiro byte e o primeiro paint. Um template onde esse intervalo é maior do que nos outros carrega mais ficheiros destes.
- LCP render delay. Procure templates onde o render delay represente uma parte substancial do LCP. O CSS bloqueador é uma das causas dessa espera; o DevTools (secção seguinte) mostra se essa página tem algum.
O CrUX apresenta as mesmas métricas no p75 para a sua origem ou para um URL, sem indicar qual é o template lento.

CoreDash numa loja de exemplo, acme-pagespeed.com, mobile, p75: as páginas de produto e de categoria são as mais lentas.
Como encontrar os ficheiros bloqueadores no DevTools?
Abra a página no Chrome, vá ao painel Performance, defina a rede para Slow 4G e o CPU para 4x slowdown, e grave um reload. A barra lateral de Insights lista os Render-blocking requests. Clique aí e o DevTools destaca cada request bloqueador na faixa Network.

Cada barra vai desde o momento em que o request começou até à chegada do seu último byte. Procure o request que termina por último antes do marcador do FCP: o paint esperou por esse. Um request de CSS que só começa quando outro termina é um @import. Quando nada bloqueia, a barra lateral diz "No render-blocking requests for this navigation".
Como resolver os render-blocking requests?
O URL na tabela do Lighthouse indica de onde vem cada ficheiro, e isso dita onde deve intervir.
CSS e scripts próprios
Nos seus próprios templates, aponte para este head: uma única stylesheet pequena e reduzida, e todos os scripts com defer. Assim, o primeiro paint espera apenas por esse ficheiro.
<link rel="stylesheet" href="/css/main.min.css">
<script src="/js/jquery.min.js" defer></script>
<script src="/js/gallery.min.js" defer></script> Como lá chegar é explicado mais abaixo, a começar por Reduzir e combinar o CSS.
WordPress
Os ficheiros em /wp-content/plugins/ pertencem a um plugin, /wp-content/themes/ ao tema e /wp-includes/ ao próprio WordPress.
Se não escreve código, use um plugin de otimização com estas definições:
- Ative o defer nos scripts: Load JavaScript deferred no WP Rocket, Defer JavaScript no Perfmatters, Load JS Deferred no LiteSpeed Cache. Um script com defer já não bloqueia o primeiro paint. O jQuery exige cuidados, veja abaixo.
- Mantenha Load CSS Asynchronously e critical CSS desativados, diga o que disser a velha recomendação do WordPress neste insight sobre plugins que fazem "inline critical assets". O critical CSS funciona, mas o restante CSS chega após o primeiro paint, pelo que a página se estiliza duas vezes e sofre muitas vezes shifts de layout. O custo adicional do inlining está explicado em Reduzir e combinar o CSS.
- Mantenha Remove Unused CSS desativado (Generate UCSS no LiteSpeed Cache). Gera um CSS separado para cada URL (o WP Rocket coloca-o inline no HTML) e mantém apenas as regras que encontra na página à medida que esta carrega; por isso, um elemento que um script altere mais tarde (um menu aberto, um slider) pode perder os seus estilos. O WP Rocket tem um guia inteiro dedicado aos problemas de apresentação que isto causa. Dá mais dores de cabeça do que benefícios: reduza e combine as stylesheets por si mesmo. Dá mais trabalho, mas compensa amplamente.
Muitos plugins carregam o seu CSS em todas as páginas, incluindo em páginas onde não fazem nada: o Contact Form 7 em páginas sem formulário, o WooCommerce fora da loja. Todas as stylesheets que o WordPress imprime têm um id como contact-form-7-css: a parte antes de -css é o handle que deve usar para a remover onde não é necessária:
add_action( 'wp_enqueue_scripts', function () {
if ( ! is_page( 'contact' ) ) {
wp_dequeue_style( 'contact-form-7' );
}
}, 20 ); O WooCommerce tem um filtro próprio para as suas três stylesheets, woocommerce_enqueue_styles. Para scripts próprios, o WordPress 6.3 e versões posteriores podem adicionar defer:
wp_enqueue_script( 'acme-gallery', get_stylesheet_directory_uri() . '/js/gallery.min.js', array( 'jquery' ), '2.3.0', array( 'strategy' => 'defer' ) ); O WordPress remove esse defer de novo, sem qualquer aviso, quando um script dependente do seu ainda estiver a bloquear, ou quando um script inline é inserido a seguir. Verifique a tag de script no código-fonte da página.
Só aplique defer ao jQuery com uma ferramenta que também trate das chamadas inline jQuery(...). O WordPress regista o jQuery sem defer, pelo que este bloqueia o head assim que algo depende dele; e adicionar defer manualmente quebra todas as chamadas inline jQuery(...) executadas antes. O Load JavaScript deferred do WP Rocket aplica defer ao jQuery e encapsula essas chamadas inline. O Defer JavaScript do Perfmatters deixa o jQuery de fora até ativar a opção Include jQuery; quando o fizer, navegue pela página (menu, galeria, carrinho) para confirmar que nada se partiu.
Um child theme cujo style.css comece por @import url("../storefront/style.css") cria uma cadeia de @import. Remova essa linha e carregue a stylesheet-mãe com wp_enqueue_style.
Shopify
As apps adicionam os seus ficheiros através de app embeds (Online Store, Edit theme, App embeds). O ficheiro de script de um embed carrega em async (a menos que o seu Liquid crie a sua própria tag de script), mas a stylesheet bloqueia. Desative os embeds que não usa e, após desinstalar uma app, procure no theme.liquid e nos snippets o código que ela deixou para trás.
Os temas carregam o CSS com o filtro stylesheet_tag no theme.liquid, que cria um link bloqueador. Para a stylesheet base principal, não há problema. O filtro script_tag cria um script sem defer, por isso escreva essa tag manualmente:
<!-- bloqueia o primeiro paint -->
{{ 'gallery.js' | asset_url | script_tag }}
<!-- não bloqueia -->
<script src="{{ 'gallery.js' | asset_url }}" defer></script> O Shopify já envia 103 Early Hints para até 10 ficheiros render-blocking no head, pelo que esses ficheiros começam cedo de qualquer forma; o que ainda pode alterar é quantos existem e qual o seu tamanho. Conte que a stylesheet do accelerated checkout continue na lista (veja abaixo).
Next.js
No App Router, cada import de CSS transforma-se num link de stylesheet no topo do head, e o React não faz o paint até que este tenha carregado. O Next.js junta-os em alguns chunks, pelo que a solução passa por ter menos CSS. Mova o CSS que é usado apenas por algumas rotas do CSS global para CSS Modules: o CSS global importado no root layout vai para todas as rotas; um CSS Module vai apenas para as rotas que o importam. Mais informações sobre como o Next.js constrói os seus ficheiros CSS.
O Next.js carrega os seus próprios scripts com async ou defer. Um script bloqueador num site em Next.js foi adicionado manualmente ao layout por alguém. Carregue-o com next/script, que por omissão só o carrega quando o Next.js tiver começado a hidratar a página:
import Script from 'next/script'
<Script src="https://example.com/widget.js" strategy="afterInteractive" /> Google Fonts e outros domínios
O link do Google Fonts é uma stylesheet bloqueadora em fonts.googleapis.com, e os ficheiros dos tipos de letra vêm de um segundo domínio, fonts.gstatic.com. O Lighthouse atribuiu a esse ficheiro de 0,5 kB o Duration mais longo: contabiliza a nova ligação. Aloje os tipos de letra no seu próprio servidor e coloque as regras @font-face na sua stylesheet; dessa forma, o request e ambas as ligações desaparecem. No Next.js, o next/font já faz isto.
Ferramentas de consentimento, testes A/B e outros ficheiros em que não deve mexer
- Uma ferramenta de consentimento com auto-blocking (Cookiebot, OtAutoBlock da OneTrust, autoblocker da Usercentrics): tem de correr antes de qualquer outro script para os impedir de carregar, pelo que é síncrona por conceção. A alternativa é o modo manual, onde marca cada script de cookies manualmente. Se o esforço compensa é, antes de mais, uma questão legal. Um preconnect ao domínio da ferramenta, pelo menos, inicia a ligação mais cedo.
- Um snippet de testes A/B (Optimizely, AB Tasty, Convert): propositadamente síncrono, para que os visitantes não vejam o original piscar antes da variante. Remova-o quando nenhum teste estiver a decorrer.
- O content_for_header do Shopify: todos os temas precisam dele e não é possível editá-lo. Em todas as cinco lojas verificadas para este artigo, ele adicionou uma stylesheet bloqueadora para o accelerated checkout, a accelerated-checkout-backwards-compat.css. Deixe-a ficar.
Reduzir e combinar o CSS
Mantenha o CSS render-blocking reduzido a poucas stylesheets, cada uma com menos de cerca de 15 kB comprimidos. 15 kB é aproximadamente o que uma nova ligação transfere no primeiro round trip.

Seis stylesheets render-blocking em Slow 4G no painel Network do DevTools. A verde está a espera pelo primeiro byte, igual para todos os ficheiros. A azul está o download, que cresce com o tamanho do ficheiro.
- Combine os pequenos ficheiros adicionados pelo tema e pelos plugins. Cada stylesheet espera um round trip completo antes de receber o primeiro byte — cerca de 0,6 s em Slow 4G —, seja qual for o seu tamanho. Um ficheiro de 0,3 kB sujeita-se a toda essa espera por quase nada.
- Reduza ou divida um ficheiro grande. Após a mesma espera, o ficheiro de 14 kB demorou mais 0,4 s a chegar. O ficheiro de 60 kB precisou de mais um segundo para descarregar, e a página continuou em branco até ele estar disponível.
- Remova as regras que a página não usa. O separador Coverage no DevTools mostra por ficheiro quanto do CSS a página nunca usa. Na mediana dos sites, esse valor é de 89% (State of CWV, cobertura do Chrome na página inicial).
- Não coloque todo o CSS num único ficheiro grande. Todo o CSS, sem redução, num único ficheiro de 68 kB fez o paint mais tarde do que com os nove ficheiros separados. O ficheiro grande partilhou a largura de banda com os scripts com defer e com a imagem hero, enquanto com nove ficheiros os render-blocking requests obtiveram a maior parte dela.
- Não coloque o CSS inline. O CSS inline fica no HTML, e o HTML é o primeiro ficheiro de que o browser precisa: tudo o resto espera por ele. Portanto, fazer inlining torna o único ficheiro pelo qual tudo espera maior e mais lento. Mais importante ainda: normalmente, o browser não guarda o HTML em cache, pelo que cada visualização de página descarrega esse CSS novamente, enquanto uma stylesheet separada fica guardada em cache após a primeira página. Entre os sites com um TTFB abaixo de 900 ms e um a cinco requests bloqueadores, 95,9% dos que não usam CSS inline têm um bom FCP, contra 90,8% dos que colocam mais de 300 kB inline (State of CWV).
- Não separe "o resto" do CSS para carregar mais tarde. O velho truque de
media="print"só funciona para CSS que nunca está no primeiro ecrã, e raramente se sabe isso para todas as páginas e tamanhos de ecrã: se falhar na previsão, a página faz primeiro o paint sem estilos.
Substituir todos os @import
Dê a cada ficheiro importado o seu próprio link no HTML ou combine-o na stylesheet-mãe. A remoção do @import na página de produto antecipou o primeiro paint em 137 ms assim que os scripts foram colocados com defer. Com os scripts ainda a bloquear, poupou 33 ms: o jQuery chegou aproximadamente à mesma hora que a stylesheet importada, pelo que o paint esperou pelo jQuery de qualquer maneira.
Adiar os scripts
Adicione defer a todos os scripts no head de que o primeiro paint não precisa. Os scripts de módulo já têm defer por omissão. O async também remove o script da lista, mas ainda pode ser executado antes do primeiro paint e bloquear a main thread, pelo que o defer é a melhor opção por omissão. Hoje em dia, os scripts são a menor parte deste insight: aplicar defer a ambos os scripts poupou 24 ms, porque o CSS terminou mais tarde de qualquer forma. Saiba mais em async vs defer, head vs footer JavaScript e 14 methods to defer JavaScript.
Antecipar a stylesheet principal com 103 Early Hints
Com os 103 Early Hints, o servidor indica ao browser quais os ficheiros a descarregar enquanto ainda está a gerar o HTML. Aplique o hint à sua stylesheet principal:
HTTP/2 103
link: </css/main.min.css>; rel=preload; as=style Compensa quando o servidor precisa de tempo para gerar a página. A stylesheet é descarregada durante esse tempo, pelo que o ganho é, no máximo, o tempo de reflexão do servidor; já uma página servida a partir da cache de uma CDN ganha muito pouco. A Cloudflare tem uma opção dedicada (Speed, Settings, Content Optimization) e gera os hints a partir dos cabeçalhos Link enviados pelo servidor. O Apache 2.4.58 e versões posteriores dispõem de H2EarlyHint.
Verifique o LCP depois. Com o CSS disponível mais cedo, os tipos de letra nele referenciados também começam mais cedo: na página de produto, a fonte Font Awesome de 156 kB retirou largura de banda à fotografia do produto, e o LCP ocorreu mais tarde. O Lighthouse mantém o ficheiro com early hint na lista de qualquer forma, com 0,0 KiB. Mais pormenores sobre os 103 Early Hints, e sobre por que razão um simples preload de uma stylesheet que também está ligada não ajuda.
Evitar fetchpriority="low" numa stylesheet
Uma recomendação comum é atribuir fetchpriority="low" ao CSS de que o primeiro ecrã não precisa. É um antipadrão. No head, o Chrome desce essa stylesheet apenas um nível, de prioridade highest para high, e continua à espera dela antes do primeiro paint. O Lighthouse decide o que bloqueia com base na prioridade durante a simulação, pelo que trata o ficheiro como se tivesse desaparecido: sem Duration e com um FCP simulado mais rápido.
Apliquei isto a quatro stylesheets. O Lighthouse com throttling simulado baixou o FCP de 2,0 s para 1,60 s e subiu a pontuação de 96 para 97. No Chrome, o primeiro paint passou de 2122 ms para 2114 ms; ou seja, os visitantes esperam exatamente o mesmo que antes.

Lighthouse, throttling simulado

Chrome no telemóvel, mesma página
No momento indicado pelo Lighthouse como FCP, o Chrome ainda mostra um ecrã em branco.
Como verificar se a correção funcionou?
Execute novamente o Lighthouse em mobile. Com a correção, a pontuação passou de 96 para 100 e o FCP simulado de 2,0 s para 1,1 s, e o insight passou de vermelho com doze ficheiros para laranja com apenas um: a stylesheet de 6,6 kB.

Antes

Depois
Lighthouse 13.5.0, mobile, throttling simulado.
Execute três vezes e escolha o resultado mediano: na mesma página, o FCP simulado variou 1,5 s entre execuções.
O CoreDash mostra o FCP e o LCP render delay logo a partir das visitas seguintes. O CrUX e o Search Console mostram os últimos 28 dias; logo, duas semanas após a correção, metade do que apresentam ainda é do site antigo.
Quer saber se é o CSS bloqueador que mantém o seu FCP ou LCP no vermelho em mobile? Numa Core Web Vitals power hour, abrimos juntos o seu field data e um trace da sua página, e fica com a lista exata dos ficheiros a reduzir, combinar ou adiar.
O score do Lighthouse não conta a história toda.
Os teus visitantes estão em Android sobre 4G. Eu analiso o que eles apanham na prática.
Analisar dados reais