WOFF2, subconjunto e carregamento sem mudança de layout


Como otimizar fontes da web

  1. Auditoria quais arquivos de fontes, pesos e conjuntos de caracteres suas páginas realmente solicitam.
  2. Converter todas as fontes para WOFF2 e subconjunto de acordo com os personagens que seu conteúdo realmente usa.
  3. Escrever @font-face regras com unicode-range e um deliberado font-display valor.
  4. Corresponder as métricas de uma fonte substituta local para que a troca não mova seu layout.
  5. Pré-carregar apenas um ou dois arquivos necessários para o texto acima da dobra e servi-los com cabeçalhos de cache de longa duração.
  6. Medir mudança de layout e tempo de carregamento da fonte no campo e, em seguida, verifique os modos de falha listados no final.

As fontes da Web são um dos poucos recursos que podem atrasar o texto, mudar o layout e aumentar o peso da página, tudo de uma vez. Eles também são fáceis de ignorar, porque um arquivo de design mostra a fonte final e não diz nada sobre as três solicitações necessárias para chegar lá. Este tutorial apresenta um fluxo de trabalho prático para envio de fontes que carregam rapidamente e permanecem visualmente estáveis, com comandos funcionais e CSS que você pode adaptar.

A verificação de tudo isso requer dados de campo de visitantes reais, não apenas uma única execução do Lighthouse. Se você quiser coletar isso sozinho, sem cookies ou banners de consentimento, o tutorial do SitePoint em contando visitantes únicos sem cookies aborda um padrão do lado do servidor que é fácil de adaptar para armazenar as métricas descritas posteriormente neste artigo.

Índice

  • Por que as fontes diminuem a velocidade das páginas
  • Etapa 1: audite o que você envia
  • Etapa 2: converter para WOFF2 e subconjunto
  • Etapa 3: escreva as regras do @font-face
  • Etapa 4: combine as métricas da fonte substituta
  • Etapa 5: pré-carregar e armazenar em cache corretamente
  • Passo 6: Medir no Campo
  • Modos de falha e mitigações
  • Auto-hospedagem versus serviços de fontes hospedadas
  • Próximas etapas

Por que as fontes diminuem a velocidade das páginas

Um navegador não solicita um arquivo de fonte ao analisar o HTML. Ele espera até que a folha de estilo seja carregada, constrói a árvore de renderização, encontra o texto que precisa de um texto específico. font-familye só então inicia o download. Isso torna as fontes recursos descobertos tardiamente, e o atraso é incorporado ao modo como a renderização funciona.

Enquanto o arquivo está em andamento, o navegador precisa decidir o que mostrar. Dependendo do font-display valor, ele oculta o texto por um curto período, mostra uma fonte substituta imediatamente ou fornece à fonte da web uma janela muito pequena para chegar. Se o substituto e a fonte final tiverem proporções diferentes, o texto reflui quando a troca ocorre. Esse refluxo conta para a mudança cumulativa de layout.

Portanto, há três custos separados para gerenciar: o tempo antes do início da solicitação, o tamanho do arquivo e o salto visual quando a fonte substitui o substituto. Cada etapa abaixo tem como alvo um deles.

Etapa 1: audite o que você envia

Antes de alterar qualquer coisa, liste o que a página realmente carrega. Abra o DevTools, vá ao painel Rede, filtre por “Fonte” e recarregue com o cache desabilitado. Observe cada arquivo, seu tamanho e quando ele começa em relação à primeira pintura.

Você também pode listar as fontes que o navegador carregou no console:

javascript

document.fonts.ready.then(() => {
  const loaded = (...document.fonts)
    .filter((face) => face.status === 'loaded')
    .map((face) => `${face.family} ${face.weight} ${face.style}`);
  console.table(loaded);
});

As páginas tendem a coletar fontes com o tempo. Um design que começou com uma espessura regular e uma em negrito termina com seis espessuras, duas em itálico e uma fonte de ícone usada para três ícones. Corte qualquer coisa que não esteja visivelmente usada. Cada peso que você remove é uma solicitação e algumas dezenas de kilobytes que você nunca precisa otimizar.

Etapa 2: converter para WOFF2 e subconjunto

WOFF2 é o formato a ser direcionado. Ele usa compactação Brotli e normalmente é cerca de 30% menor que o WOFF, e todos os navegadores atuais o suportam. Para a maioria dos projetos não há mais uma boa razão para enviar TTF, OTF ou EOT para navegadores, portanto, uma única fonte WOFF2 em seu @font-face regra é suficiente.

O subconjunto vai além. Um arquivo de fonte contém milhares de glifos, e um site típico em inglês ou na Europa Ocidental usa algumas centenas. O fonttools pacote envia um comando chamado pyftsubset isso remove o resto.

festa

pip install fonttools brotli

pyftsubset Inter-Regular.ttf \
  --unicodes="U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD" \
  --layout-features="*" \
  --flavor=woff2 \
  --output-file=inter-regular-latin.woff2

A lista Unicode acima cobre latim básico, pontuação latina-1 e alguns símbolos comuns. --layout-features="*" mantém tabelas de kerning e ligadura, que são importantes para a aparência do texto. Se você descartá-los para economizar bytes, a tipografia degrada visivelmente. O pacote brotli é necessário para --flavor=woff2 para trabalhar.

Duas notas práticas. Primeiro, verifique a licença da fonte antes de modificar um arquivo. A maioria das licenças abertas permite subconjuntos e conversão de formato, mas algumas restringem como uma versão modificada pode ser nomeada ou redistribuída. Segundo, se uma fonte for variável, pyftsubset mantém os eixos de variação por padrão, para que um arquivo possa substituir vários pesos estáticos. Se isso é menor depende de quantos pesos você estava usando. Dois pesos estáticos costumam ser mais leves do que um arquivo variável com uma ampla faixa de pesos.

Para uma conversão única ou para visualizar a aparência de uma fonte antes de você se comprometer com ela, uma ferramenta baseada em navegador é mais rápida do que configurar o Python. Fontemente oferece um conversor entre TTF, OTF, WOFF, WOFF2 e EOT, além de um gerador para a correspondência @font-face CSS. Para qualquer coisa repetível, coloque pyftsubset ou uma ferramenta como glyphhanger em seu script de construção para que a saída seja regenerada sempre que a fonte de origem ou seu conteúdo for alterado.

Etapa 3: escreva as regras do @font-face

Declare cada subconjunto com seu próprio unicode-range. O navegador só baixa um arquivo quando a página contém caracteres nesse intervalo, portanto, uma página somente em latim nunca busca os arquivos em cirílico ou grego.

css

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

@font-face {
  font-family: "Inter";
  src: url("/fonts/inter-regular-latin-ext.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0100-02AF, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF,
    U+2113, U+2C60-2C7F, U+A720-A7FF;
}

O font-display o valor merece uma escolha deliberada em vez de um padrão copiado e colado. O padrão do navegador é blockque oculta o texto por alguns segundos enquanto a fonte é carregada.

Valor Comportamento Bom para Troca
block Curto período invisível, depois troque Fontes de ícones, logotipos Texto invisível em conexões lentas
swap Fallback mostrado de uma vez, troque sempre que a fonte chegar Corpo do texto, maioria dos sites Refluxo visível no momento da troca
fallback Período invisível muito curto, janela de troca limitada Corpo do texto com orçamentos apertados A fonte pode nunca ser aplicada em um primeiro carregamento lento
optional Janela minúscula, caso contrário, substituto para essa visualização de página Páginas que priorizam o desempenho Alguns visitantes de primeira viagem nunca veem a fonte da web

swap é a escolha habitual. optional vale a pena considerar quando a estabilidade é mais importante do que a tipografia da marca na primeira visita, pois evita quase totalmente a mudança de layout. Os visitantes que retornam obtêm a fonte em cache e a veem normalmente.

Etapa 4: combine as métricas da fonte substituta

Usando swap significa que o layout irá saltar, a menos que a fonte substituta ocupe aproximadamente o mesmo espaço que a fonte real. CSS possui descritores para isso: size-adjust, ascent-override, descent-overridee line-gap-override. Você define um segundo @font-face que aponta para uma fonte do sistema local e a ajusta para se parecer com a fonte da web.

css

@font-face {
  font-family: "Inter Fallback";
  src: local("Arial");
  size-adjust: 107.4%;
  ascent-override: 90.2%;
  descent-override: 22.5%;
  line-gap-override: 0%;
}

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

As porcentagens acima são ilustrativas e não serão corretas para todos os pares de fontes e substitutos. Calcule o seu próprio a partir das métricas da fonte. Ferramentas como Capsize, o fontaine pacote, e a otimização de fontes incorporada em algumas estruturas pode gerar esses valores para você. Após aplicá-los, recarregue com o cache desabilitado e uma conexão acelerada e observe se o texto ainda salta no momento da troca. Uma pequena mudança residual é normal. Um grande significa que os números estão errados.

Etapa 5: pré-carregar e armazenar em cache corretamente

Como as fontes são descobertas tardiamente, uma dica de pré-carregamento permite que o navegador inicie o download mais cedo. Pré-carregue apenas o arquivo usado pelo texto acima da dobra, geralmente o peso normal do subconjunto primário.

HTML

<link
  rel="preload"
  href="/fonts/inter-regular-latin.woff2"
  as="font"
  type="font/woff2"
  crossorigin
/>

O crossorigin O atributo é obrigatório mesmo quando a fonte é veiculada em sua própria origem. As fontes são buscadas no modo CORS anônimo e um pré-carregamento sem o atributo não corresponde à solicitação posterior. O resultado é o mesmo arquivo baixado duas vezes, o que é pior do que nenhum pré-carregamento.

As fontes raramente mudam, então armazene-as em cache por um longo tempo. Dê a cada arquivo um hash de conteúdo em seu nome e marque-o como imutável. No Express, são algumas linhas:

javascript

const express = require('express');
const app = express();

app.use(
  '/fonts',
  express.static('public/fonts', {
    maxAge: '1y',
    immutable: true,
  })
);

Ao substituir uma fonte, altere o nome do arquivo (por exemplo inter-regular-latin.3f9a1c.woff2) e atualize o CSS. Se as fontes forem veiculadas de uma origem diferente, como um subdomínio CDN, essa origem deverá enviar um Access-Control-Allow-Origin cabeçalho ou os navegadores se recusarão a usar o arquivo.

Passo 6: Medir no Campo

Os resultados do laboratório mostram se uma mudança funciona em uma execução controlada. Os dados de campo mostram se funciona para visitantes reais em seus dispositivos reais. O snippet abaixo registra a mudança de layout e o momento em que as fontes terminam de carregar e, em seguida, envia ambos para seu próprio endpoint quando a página está oculta.

javascript

let cls = 0;
let fontsReadyAt = null;

new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    if (!entry.hadRecentInput) cls += entry.value;
  }
}).observe({ type: 'layout-shift', buffered: true });

document.fonts.ready.then(() => {
  fontsReadyAt = Math.round(performance.now());
});

document.addEventListener('visibilitychange', () => {
  if (document.visibilityState !== 'hidden') return;
  const payload = JSON.stringify({
    cls: Number(cls.toFixed(4)),
    fontsReadyAt,
    path: location.pathname,
  });
  navigator.sendBeacon(
    '/metrics',
    new Blob((payload), { type: 'application/json' })
  );
});

Isso resume todas as mudanças de layout, o que é uma simplificação. Os grupos oficiais de métricas Cumulative Layout Shift mudam para janelas de sessão e relatam a maior, portanto, trate o número aqui como um indicador de tendência e use o web-vitals biblioteca se precisar de um valor que corresponda ao relatório das ferramentas de pesquisa. Compare os números antes e depois de cada alteração e observe o percentil 75 em vez da média, já que dispositivos e redes lentas são onde as fontes mais prejudicam.

Modos de falha e mitigações

A otimização de fontes tem bordas nítidas e a maioria delas só aparece após o envio.

Glifos ausentes após subconjunto. Se o seu conteúdo incluir posteriormente um caractere fora do subconjunto, como um símbolo de moeda, um nome acentuado ou um símbolo adjacente a um emoji, o navegador retornará para outra fonte para esse caractere ou mostrará uma caixa vazia. Mantenha um subconjunto mais amplo para conteúdo gerado pelo usuário e teste com nomes e dados reais, em vez de lorem ipsum.

Downloads duplos devido a incompatibilidades de pré-carregamento. Uma falta crossorigin atributo ou um pré-carregamento type que não corresponde ao arquivo, faz com que o arquivo seja buscado duas vezes. Verifique se há entradas duplicadas no painel Rede após adicionar qualquer pré-carregamento.

Pré-carregando demais. Cada fonte pré-carregada compete com a folha de estilo, a imagem principal e os scripts pela largura de banda inicial. Pré-carregue um ou dois arquivos, não toda a família.

Texto invisível de fontes de ícones. Fontes de ícones com font-display: swap mostre um caractere substituto, geralmente uma letra perdida, até que a fonte chegue. Usar block para fontes de ícones ou mude para SVG embutido.

Falso negrito e itálico. Se você declarar apenas um peso regular e o CSS pedir negrito, o navegador sintetiza uma versão em negrito que parece pior que a real. Envie os pesos que você usa ou evite pedir os que você não possui.

O cache compartilhado não ajuda mais. Os navegadores agora particionam seus caches HTTP por site, portanto, uma fonte que um visitante baixou de um serviço hospedado em outro site não conta como armazenada em cache no seu. O velho argumento para hospedagem de fontes de terceiros, de que provavelmente já está armazenado em cache, é muito mais fraco do que costumava ser.

Problema Sintoma Consertar
Subconjunto muito estreito Caixas ou glifos substitutos estranhos Ampliar unicode-rangeadicione um segundo subconjunto
Pré-carregar sem crossorigin Fonte baixada duas vezes Adicione o atributo, combine type
Métricas substitutas erradas O texto ainda salta na troca Recalcular valores de substituição
Muitos pesos Carga útil de fonte grande Remova pesos não utilizados, considere uma fonte variável
Cabeçalho CORS ausente no CDN Fonte bloqueada no console Enviar Access-Control-Allow-Origin

Auto-hospedagem versus serviços de fontes hospedadas

Os serviços hospedados eliminam o trabalho de subconjunto e serviço e, para um projeto pequeno, essa conveniência é real. O custo é uma conexão extra com uma origem de terceiros, menos controle sobre cache e font-displaye uma questão de privacidade: o endereço IP do visitante chega a esse provedor em cada solicitação não armazenada em cache, o que algumas organizações europeias trataram como uma preocupação de conformidade. A auto-hospedagem lhe dá controle sobre todos os três, ao preço de possuir a etapa de construção descrita acima.

Uma regra razoável: se a tipografia faz parte do seu produto ou se você se preocupa com as últimas centenas de milissegundos, hospede-se sozinho. Se você envia um site pequeno e as fontes são um detalhe menor, um serviço hospedado com display=swap e um preconnect dica é um padrão sensato. Em ambos os casos, a etapa de medição é o que informa qual deles está realmente funcionando.

Próximas etapas

Agora você tem um fluxo de trabalho que reduz o número de solicitações, reduz cada arquivo, evita texto invisível e limita a mudança de layout no momento da troca. A ordem é importante: auditar primeiro, porque remover uma fonte é melhor do que otimizá-la, e medir por último, porque os números indicam se as etapas anteriores valeram a pena.

Possíveis acompanhamentos:

  • Adicione a verificação de carregamento de fonte ao pipeline de CI para que um novo peso ou um arquivo inchado falhe na compilação.
  • Teste uma fonte variável em relação aos seus pesos estáticos atuais e compare o total de bytes transferidos.
  • Tentar font-display: optional em um pequeno conjunto de páginas e compare a mudança de layout com swap.
  • Gere substituições de métricas substitutas automaticamente como parte do build, e não manualmente.



Source link