Critical 9: como extrair o CSS crítico sem navegador (e quando você realmente precisa)

Critical 9, publicado em 13 de setembro de 2026, extrai o CSS crítico sem navegador: em páginas que já trazem seu HTML renderizado calcula o CSS acima da dobra em milissegundos, e só abre Chromium (via Playwright) quando o HTML é um shell vazio de SPA. É uma reescrita do zero da ferramenta de Addy Osmani (~10,3k estrelas no GitHub), e o resultado prático é claro: o caso comum —saída estática, SSR ou MPA— já não precisa de um navegador headless no seu build.

O que é CSS crítico?

O CSS crítico (critical CSS) é o subconjunto de estilos necessário para pintar a primeira tela, ou seja, o conteúdo que fica acima da dobra. Por padrão, cada <link rel="stylesheet"> do <head> é render-blocking CSS: o navegador não pinta nada até baixá-lo e processá-lo. Ferramentas como Critical extraem as regras que dão estilo ao conteúdo visível, as inserem em um <style> no início do <head> e carregam o resto da folha sem bloquear o primeiro pintado.

Como o CSS crítico melhora o LCP e o First Contentful Paint?

Ao remover folhas de estilo do caminho crítico, o navegador pode pintar a primeira tela só com o HTML. O README de Critical o apresenta como uma das alavancas mais diretas sobre o Largest Contentful Paint (LCP), e as notas da versão falam em chegar mais rápido ao primeiro pintado (First Contentful Paint).

O que muda no Critical 9?

A mudança principal: Critical agora inclui dois motores e escolhe entre eles automaticamente.

  • static: compara as regras CSS com o DOM entregue. Sem navegador, executa em milissegundos. Pensado para saída SSG, SSR ou MPA que já traz a marcação real.
  • render: carrega a página em um viewport real e mede o que de verdade se pinta acima da dobra (usa Playwright). Pensado para shells de SPA ou quando você quer um conjunto ajustado e preciso por viewport.

É uma mudança de fundo. Até a v8, Critical usava Penthouse internamente, e Penthouse sempre lançava um navegador headless. Agora a primeira coisa que tenta é uma passada sem navegador.

Além disso:

  • Núcleo mais leve: reconstruído sobre lightningcss, css-tree e linkedom, com três dependências de runtime. Playwright é uma dependência peer opcional que é importada só quando necessário, então a instalação padrão não baixa nenhum navegador.
  • Saída determinística: a mesma entrada produz uma saída idêntica byte a byte.
  • Compatível com CSP rigorosa: não adiciona scripts inline.
  • Nova API: a v9 é uma versão maior com uma API e um conjunto de opções novos. Se você vem da v8, revise o README em vez de transferir sua configuração como está.

Também incorpora um servidor MCP e um report estruturado em cada execução, pensados para agentes de código e scripts de build.

Como Critical escolhe o motor?

Com engine: "auto" (o valor padrão), Critical inspeciona o HTML entregue. Se o documento já contém conteúdo renderizado, usa o motor estático. Se é um shell vazio — por exemplo <div id="root"></div> sem marcação ainda —, não há nada com que comparar sem navegador, então passa ao motor de renderização. Sempre te indica qual motor usou e por quê, e você pode fixá-lo com engine: "static" ou engine: "render".

É possível extrair o CSS crítico sem navegador?

Sim, desde que seu HTML já contenha a marcação da página: geradores de sites estáticos, páginas renderizadas no servidor e sites multipágina clássicos.

Um detalhe: sem navegador não existe dobra. Por padrão, o motor estático insere todo o CSS usado, não só o da primeira tela. Para ajustá-lo sem navegador, adicione data-critical-fold ao contêiner que agrupa o conteúdo da primeira tela e o motor estático limitará a comparação àquela subárvore.

Como instalar Critical 9?

Instale como uma dependência de desenvolvimento:

npm install --save-dev critical

Isso é suficiente para o motor estático. O motor de renderização também precisa de Playwright e um navegador:

npm i -D playwright && npx playwright install chromium

CLI

# Otimiza um diretório de build em seu site (insere o CSS crítico e adia o resto)
critical ./dist --inline --write

# Mostra o que faria e por quê, sem escrever nada
critical ./dist --explain

# Força uma passada com navegador real para uma SPA
critical app.html -e render -i > out.html

# União das dobras de celular e desktop
critical page.html --dimensions 390x844,1300x900 -i

O viewport padrão do motor de renderização é 1300×900; você pode alterá-lo com -w e -h, ou usar --dimensions para vários de uma vez.

API

import { critical } from "critical";

const { html, css, report } = await critical({
  src: "dist/index.html",
  inline: true,
});

critical() nunca escreve em disco por conta própria: devolve o resultado e você decide onde salvar html e css.

Docker

A imagem oficial inclui Playwright e Chromium, então ambos os motores funcionam sem configuração adicional:

docker run --rm -v "$PWD/dist:/site" ghcr.io/addyosmani/critical:master \
  critical . --inline --write

O Critical funciona com Node 20?

Não. Critical 9 requer Node.js ≥ 22.13, portanto Node 20 e as primeiras versões da 22.x não são compatíveis. Se sua imagem de CI ainda está no Node 20, mantenha a linha v8 ou atualize o runtime antes de atualizar Critical.

Quando usar o mecanismo de renderização em vez do estático?

Use o mecanismo de renderização em três casos:

  • Shells de SPA não renderizados. Se o HTML no momento do build é apenas <div id="root"></div>, não há nada para comparar estaticamente. O modo automático escolherá render de qualquer forma; defini-lo apenas ignora a verificação.
  • Páginas longas. O mecanismo estático insere todo o CSS usado, então estilos do rodapé, FAQ ou tabela de preços podem acabar no payload bloqueante. O mecanismo de renderização sabe onde está a dobra e os deixa de fora.
  • Múltiplos viewports. Com --dimensions você obtém um único conjunto crítico que cobre celular e desktop.

Para todo o resto, o caminho estático é mais rápido e mantém os navegadores fora do seu pipeline.

Critical ou Beasties?

Depende de como seu site é renderizado. Beasties — o sucessor mantido de Critters, do Google, e o mecanismo por trás de optimizeCss no Next.js — também funciona sem navegador e é a opção mais rápida para páginas pré-renderizadas.

Os mantenedores de Critical publicam uma comparação no próprio repositório (COMPARISON.md) que reconhece abertamente quando Beasties é mais adequado: sites SSG/SSR simples, especialmente se seu framework já o integra. Critical, com seu mecanismo de renderização, é adequado quando você precisa de um conjunto crítico preciso por viewport, tem páginas longas ou trabalha com shells de SPA que não quer pré-renderizar separadamente.

Seu benchmark mostra um payload inserido 63,8% menor do que o Beasties em uma página longa. É um número publicado pelos próprios mantenedores, que também advertem que depende do caso de teste: é apenas um par de páginas, não um corpus. A ideia estrutural se sustenta: um mecanismo que conhece o viewport não insere CSS abaixo da dobra, então seu payload não cresce com o comprimento da página.

No momento da publicação desta nota, Critical não tinha plugins oficiais para Vite, webpack, Nuxt ou Next (sua própria comparação os marca como “not yet”): ele é executado como etapa posterior ao build, a partir da CLI ou da API.

Como usar Critical em CI?

Duas propriedades tornam Critical 9 adequado para um pipeline de build:

  • Determinismo. A saída é idêntica byte a byte para a mesma entrada, então você pode versioná-la e revisar diffs sem ruído. --json emite um relatório legível por máquina: mecanismo usado, regras preservadas, bytes bloqueantes removidos, avisos e tempo.
  • Compatibilidade com CSP. As folhas diferidas são substituídas por um <link rel="preload"> no <head> e o link real da folha é movido para o final do <body>. Não há manipuladores de eventos inline nem fallback <noscript>, então funciona com uma política script-src estrita. Para um style-src estrito, passe inline: { nonce: "…" } e o <style> inserido carregará seu nonce. Se quiser que uma folha não seja tocada, adicione data-critical-skip ao seu <link>.

Se você orquestra builds a partir de um agente, Critical também expõe um servidor MCP com a ferramenta optimize_critical_css, que retorna o mesmo relatório.

Procurando por mais ferramentas de CSS? Confira nossa seleção de 70 recursos CSS selecionados manualmente.