Otimização de Fontes Web em 2026: woff2, font-display, size-adjust e Variable Fonts

Guia prático de otimização de fontes web em 2026: woff2, font-display swap, size-adjust com ascent-override, preload com fetchpriority, variable fonts, subsetting unicode-range e checklist para zerar CLS e acelerar LCP.

Olha, vou ser sincero: fontes web mal otimizadas continuam sendo uma das maiores vilãs por trás de CLS alto, LCP atrasado e aquele FOIT/FOUT irritante que ainda assombra a web em 2026. Já vi sites que passam folgado nos Core Web Vitals em todos os outros aspectos tropeçarem feio porque o @font-face bloqueia a renderização — ou pior, porque o fallback e a fonte real têm métricas tão diferentes que a página dança na frente do usuário.

Este guia mostra a stack completa de otimização de fontes que uso na prática hoje — do velho conhecido woff2 ao descritor size-adjust, passando por preload, fetchpriority, variable fonts e subsetting com unicode-range. O objetivo é simples: tirar tipografia da lista de gargalos de performance, de uma vez.

Por que fontes web ainda quebram performance em 2026

Cada fonte personalizada significa, no mínimo, uma requisição de rede crítica e um repaint quando o navegador troca o fallback pela fonte de verdade. Em 4G médio, um arquivo woff2 de 35 KB pode jogar entre 200 e 400 ms no LCP se você não pré-carregar. E tem um detalhe pior ainda: se as métricas do fallback (x-height, advance width, essas coisas) estiverem muito longe da fonte final, a troca causa layout shift visível — e lá se vai seu CLS para fora do limite de 0,1.

Os três sintomas que você precisa eliminar são clássicos:

  • FOIT (Flash of Invisible Text): texto fica invisível até a fonte chegar. Péssimo pro LCP quando o elemento principal da página é texto.
  • FOUT (Flash of Unstyled Text): o texto aparece com fallback e depois "salta" pra fonte final. Péssimo pro CLS.
  • Render-blocking de @font-face: declarações em CSS externo só são descobertas depois que o CSS termina de baixar e ser parseado, atrasando o início do download da fonte.

woff2 com Brotli: o ponto de partida não negociável

Em 2026, woff2 tem suporte universal e já vem com compressão Brotli embutida. Servir ttf, otf ou o woff antigo (versão 1) é jogar 30 a 50% mais bytes no fio sem ganhar nada em troca. Vale a pena dar uma olhada no seu CDN e eliminar formatos legados de uma vez:

@font-face {
  font-family: "Inter";
  src: url("/fonts/inter-var.woff2") format("woff2-variations"),
       url("/fonts/inter-var.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

O fallback duplo é um truque pequeno mas útil — ele permite que browsers antigos sem suporte a woff2-variations ainda usem o mesmo arquivo como woff2 estático.

font-display: a decisão que define seu CLS e LCP

O descritor font-display controla dois períodos: o block period (em que o texto fica invisível) e o swap period (em que o fallback é mostrado). As cinco opções, na prática:

  • auto — comportamento padrão, geralmente equivalente a block. Evite. Sério.
  • block — block period de até 3s, depois swap. Causa FOIT pesado.
  • swap — block period de 100ms, swap infinito. Bom pro LCP (texto aparece rápido), mas pode piorar CLS se você não tomar cuidado.
  • fallback — block period de 100ms, swap period de 3s. Compromisso razoável.
  • optional — block period de 100ms, sem swap se a fonte demorar. Melhor pro CLS; ideal quando a fonte é estilística e não funcional.

Minha regra prática para 2026: use swap combinado com size-adjust e métricas de fallback ajustadas para neutralizar o layout shift. Isso te dá o melhor dos dois mundos. Reserve optional para fontes secundárias — cabeçalhos decorativos, citações, esse tipo de coisa.

Eliminando CLS com size-adjust, ascent-override e descent-override

Honestamente, essa é a técnica que mudou o jogo nos últimos anos: definir uma fonte fallback com métricas idênticas às da fonte web, de forma que a troca não cause reflow nenhum. Os descritores foram padronizados pelo CSS Fonts Module Level 4 e têm suporte total em Chrome, Firefox e Safari desde 2023.

/* Fonte fallback ajustada para casar metricas com Inter */
@font-face {
  font-family: "Inter Fallback";
  src: local("Arial");
  size-adjust: 107%;
  ascent-override: 90%;
  descent-override: 22%;
  line-gap-override: 0%;
}

body {
  font-family: "Inter", "Inter Fallback", sans-serif;
}

Para gerar os valores corretos, use o utilitário Fontaine (npm fontaine) ou o capsize. Os dois leem o arquivo da fonte real e calculam os overrides necessários — você não precisa adivinhar nada. Resultado típico que vejo em produção: CLS cai de 0,15–0,25 para perto de zero, sem precisar mudar para font-display: optional.

Preload com fetchpriority: priorizando a fonte do LCP

Se o seu LCP é um texto (heading principal, parágrafo de hero, etc.), pré-carregue a fonte usada nele. Sem preload, o navegador só descobre a fonte depois de parsear o CSS — e isso adiciona um round-trip inteiro à cadeia crítica. Não é trivial.

<link rel="preload"
      href="/fonts/inter-var.woff2"
      as="font"
      type="font/woff2"
      crossorigin
      fetchpriority="high">

Três detalhes que muita gente erra (eu já errei também, confesso):

  1. crossorigin é obrigatório, mesmo para fontes do mesmo domínio. Sem ele, o navegador baixa a fonte duas vezes — sim, duas.
  2. type="font/woff2" permite que browsers sem suporte simplesmente ignorem o preload.
  3. fetchpriority="high" (suportado em Chromium e Safari 17+) sobe a prioridade acima de scripts e CSS não-crítico.

Mas atenção: limite-se a uma ou duas fontes preloadadas. Preload em excesso compete com a imagem do LCP e acaba degradando a performance que você queria melhorar. É uma ironia que vale lembrar.

Variable Fonts: um arquivo, todos os pesos

Em vez de servir inter-400.woff2, inter-500.woff2, inter-700.woff2 (cada um com seus 25 a 40 KB), uma única variable font cobre toda a faixa de pesos com tamanho um pouco maior — algo entre 60 e 90 KB. Para sites que usam três pesos ou mais, é economia líquida na largura de banda.

@font-face {
  font-family: "Inter";
  src: url("/fonts/inter-var.woff2") format("woff2-variations");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

h1 { font-weight: 800; }
p  { font-weight: 400; }
strong { font-weight: 600; }

Confira no DevTools (aba Network) se você não está acidentalmente baixando arquivos estáticos junto com a variable font. Já vi isso acontecer em projetos onde alguém esqueceu de remover os @font-face antigos.

Subsetting com unicode-range: pague só pelos glyphs que usa

Uma fonte completa cobre Latin, Latin Extended, Cyrillic, Greek e Vietnamese — facilmente 200 KB. Mas se seu site é só em português, o que você precisa de fato é Latin + Latin Extended-A, talvez uns 40 KB no total. Use unicode-range para que o navegador só baixe o subset quando algum caractere daquele intervalo realmente aparecer na página:

@font-face {
  font-family: "Inter";
  src: url("/fonts/inter-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC,
                 U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074,
                 U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215;
  font-display: swap;
}

@font-face {
  font-family: "Inter";
  src: url("/fonts/inter-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020,
                 U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F;
  font-display: swap;
}

Use glyphhanger ou fonttools subset (Python) para gerar os subsets a partir do TTF original. É menos doloroso do que parece — escreve um script uma vez e nunca mais pensa no assunto.

Self-hosting vs Google Fonts em 2026

Aqui vai uma opinião que pode soar polêmica para alguns: desde que o Chrome 86 particionou o HTTP cache por origem, o argumento clássico de "Google Fonts é cacheado entre sites" simplesmente deixou de existir. Em 2026, self-hosting é mais rápido em praticamente todos os cenários. Não é nem perto de ser disputa.

  • Elimina a conexão extra com fonts.gstatic.com (handshake TLS de 100–300 ms).
  • Permite preload no HTML (impossível com Google Fonts CDN sem hardcodar a URL atual, que muda).
  • Permite controle total sobre cache headers (immutable, 1 ano, etc.).
  • Resolve o risco de GDPR — Google Fonts já foi alvo de processos por logging de IPs na UE.

Use serviços como Fontsource (npm) ou simplesmente baixe direto do Google Fonts e sirva do seu próprio CDN. É trabalho de dez minutos.

Cache headers: sirva fontes uma única vez

Fontes têm hash no nome do arquivo (gerado pelo bundler) ou são versionadas de alguma forma. Sirva com cache imutável de longa duração e pronto:

# nginx
location ~* \.(woff2|woff)$ {
  add_header Cache-Control "public, max-age=31536000, immutable";
  add_header Access-Control-Allow-Origin "*";
}

Com immutable, o navegador nem revalida (zero 304s) — a fonte é servida do disco em menos de 5 ms.

Checklist completo para auditar fontes hoje

  1. Abra DevTools → Network → filtro Font. Conte quantos arquivos foram baixados.
  2. Para cada um, verifique: o formato é woff2? Tem Cache-Control: immutable? O tamanho está <100 KB?
  3. Rode o Lighthouse e procure pelas auditorias "Ensure text remains visible during webfont load" e "Avoid enormous network payloads".
  4. Use o painel Performance → seção Web Vitals: o LCP element é texto? Se sim, a fonte dele está preloadada?
  5. Rode capsize ou fontaine e gere os overrides para cada fonte. Aplique no CSS.
  6. Meça CLS antes e depois com PageSpeed Insights ou CrUX. A meta é <0,05.

FAQ

font-display: swap ou optional para melhor Core Web Vitals?

Use swap com size-adjust e overrides de métricas. Isso te dá o melhor LCP (texto aparece em 100 ms) sem degradar o CLS, porque as métricas do fallback são praticamente idênticas às da fonte final. optional só vence quando você aceita que usuários em conexão lenta podem nunca ver a fonte real — o que, sinceramente, raramente é desejável.

Devo preloadar todas as minhas fontes?

Não, e por favor não faça isso. Preload deve ser reservado para a fonte usada no elemento de LCP — tipicamente a fonte do heading principal ou do parágrafo de hero. Preloadar 4 ou 5 fontes força o navegador a competir com CSS e imagens críticas, e prejudica o próprio LCP. Para fontes secundárias, deixe a descoberta natural via CSS.

Variable font vence se eu uso só dois pesos?

Geralmente, não. Para 1 ou 2 pesos, dois arquivos estáticos (~50 KB no total) batem uma variable font (~80 KB). A variable font ganha a partir de 3 pesos, ou quando você usa font-weight arbitrário (550, 650) que estáticas não cobrem. Confira no Chrome DevTools Coverage antes de decidir.

Como elimino o CLS quando a fonte muda?

Defina uma fonte fallback com @font-face usando local() e os descritores size-adjust, ascent-override, descent-override e line-gap-override. Gere os valores com fontaine ou capsize — eles calculam overrides exatos comparando as métricas da fonte real com Arial ou Times. CLS típico cai de 0,2 para <0,01.

Self-hosted Google Fonts ainda vale a pena em 2026?

Sim, e mais do que nunca. Com o cache HTTP particionado por origem desde Chrome 86, o cache compartilhado do Google Fonts deixou de existir. Self-hosting elimina um DNS lookup, um TLS handshake e ainda permite preload + cache imutável de 1 ano. Use npm install @fontsource/inter ou baixe e sirva do seu próprio CDN. Simples.

Sobre o Autor Editorial Team

Our team of expert writers and editors.