Otimizar o carregamento e a renderização de WebFont

Uma fonte da Web "completa", incluindo todas as variantes de estilo (que podem ser desnecessárias) e todos os glifos (que podem não ser usados) pode resultar facilmente em um download de vários megabytes. Neste post, você vai descobrir como otimizar o carregamento de WebFonts para que os visitantes façam o download apenas do que vão usar.

Para resolver o problema de arquivos grandes que contêm todas as variantes, a regra CSS @font-face foi projetada especificamente para permitir que você divida a família de fontes em uma coleção de recursos. Por exemplo, subconjuntos de Unicode e variantes de estilo distintas.

Com essas declarações, o navegador identifica os subconjuntos e variantes úteis e faz o download do conjunto mínimo necessário para renderizar o texto, o que é muito conveniente. No entanto, se você não for cuidadoso, pode também criar um gargalo de desempenho no caminho crítico de renderização e atrasar a renderização do texto.

O comportamento padrão

O carregamento lento de fontes traz uma importante implicação oculta que pode atrasar a renderização de texto. O navegador precisa criar a árvore de renderização, que depende das árvores do DOM e do CSSOM, antes de saber quais recursos de fonte são necessários para renderizar o texto. Como resultado, as solicitações de fontes são atrasadas para bem depois de outros recursos essenciais, e o navegador pode ser impedido de renderizar o texto até que o recurso seja recuperado.

Caminho crítico de renderização da fonte

  1. O navegador solicita o documento HTML.
  2. O navegador começa a analisar a resposta HTML e a construir o DOM.
  3. O navegador descobre o CSS, o JS e outros recursos e envia solicitações.
  4. Depois de receber todo o conteúdo CSS, o navegador constrói o CSSOM e o combina com a árvore do DOM para construir a árvore de renderização.
    • As solicitações de fonte são enviadas depois que a árvore de renderização indica quais variantes da fonte são necessárias para renderizar o texto especificado na página.
  5. O navegador executa o layout e pinta o conteúdo na tela.
    • Se a fonte ainda não estiver disponível, o navegador poderá não renderizar nenhum pixel de texto.
    • Depois que a fonte está disponível, o navegador pinta os pixels de texto.

A "corrida" entre a primeira pintura do conteúdo da página, que pode ser feita logo após a criação da árvore de renderização, e a solicitação do recurso de fonte é o que cria o "problema do texto em branco", em que o navegador pode renderizar o layout da página, mas omite qualquer texto.

Ao carregar previamente as WebFonts e usar font-display para controlar como os navegadores se comportam com fontes indisponíveis, é possível evitar páginas em branco e mudanças de layout devido ao carregamento de fontes.

Pré-carregar seus recursos de WebFont

Se há alta probabilidade de que sua página precisará de uma WebFont específica hospedada em um URL que você já conheça, aproveite a priorização de recursos. O uso de <link rel="preload"> vai acionar uma solicitação para a WebFont no início do caminho crítico de renderização, sem ter que esperar que o CSSOM seja criado.

Personalizar o atraso na renderização de texto

Embora o pré-carregamento torne mais provável que uma webfont esteja disponível quando o conteúdo de uma página for renderizado, ele não oferece garantias. Você ainda precisa considerar como os navegadores se comportam ao renderizar textos que usam uma font-family que ainda não está disponível.

Na postagem Evitar texto invisível durante o carregamento de fontes, você pode conferir que o comportamento padrão do navegador não é consistente. No entanto, é possível informar aos navegadores modernos como você quer que eles se comportem usando font-display.

Compatibilidade com navegadores

  • Chrome: 60.
  • Edge: 79.
  • Firefox: 58.
  • Safari: 11.1.

Origem

Semelhante aos comportamentos de tempo limite de fonte que alguns navegadores implementam, font-display segmenta o tempo de vida de um download de fonte em três períodos principais:

  1. O primeiro é o período de bloqueio da fonte. Durante esse período, se o tipo de fonte não é carregado, qualquer elemento que tentar usá-lo deverá renderizar com um tipo de fonte de fallback invisível. Se o tipo de fonte for carregado com sucesso durante o período de bloqueio, ele será usado normalmente.
  2. O período de troca da fonte ocorre imediatamente após o período de bloqueio da fonte. Durante esse período, se o tipo de fonte não é carregado, qualquer elemento que tentar usá-lo deverá renderizar com um tipo de fonte de fallback. Se o tipo de fonte for carregado com sucesso durante o período de troca, ele será usado normalmente.
  3. O período de falha da fonte ocorre imediatamente após o período de troca da fonte. Se o tipo de fonte ainda não estiver carregado quando esse período começar, ele será marcado como uma falha de carregamento, o que causa o uso normal de fonte de fallback. Caso contrário, o tipo de fonte será usado normalmente.

Entender esses períodos significa que você pode usar font-display para decidir como sua fonte será renderizada, dependendo do sucesso e do momento do download.

Para trabalhar com a propriedade font-display, adicione-a às regras @font-face:

@font-face {
  font-family: 'Awesome Font';
  font-style: normal;
  font-weight: 400;
  font-display: auto; /* or block, swap, fallback, optional */
  src: local('Awesome Font'),
       url('/fonts/awesome-l.woff2') format('woff2'), /* will be preloaded */
       url('/fonts/awesome-l.woff') format('woff'),
       url('/fonts/awesome-l.ttf') format('truetype'),
       url('/fonts/awesome-l.eot') format('embedded-opentype');
  unicode-range: U+000-5FF; /* Latin glyphs */
}

No momento, font-display é compatível com o seguinte intervalo de valores:

  • auto
  • block
  • swap
  • fallback
  • optional

Para mais informações sobre o pré-carregamento de fontes e a propriedade font-display, consulte as seguintes postagens:

A API Font Loading

Usados juntos, <link rel="preload"> e o CSS font-display oferecem um ótimo controle sobre o carregamento e a renderização de fontes, sem acrescentar muita sobrecarga. Mas se você precisa de personalizações adicionais e está disposto a lidar com a sobrecarga introduzida pela execução do JavaScript, há outra opção.

A Font Loading API oferece uma interface de script para definir e manipular faces de fontes CSS, controlar o andamento dos downloads e modificar o comportamento padrão de carga retardada. Por exemplo, se você tiver certeza de que uma variante de fonte específica será necessária, ela pode ser definida e o navegador pode ser solicitado para iniciar uma busca imediata do recurso de fonte:

Compatibilidade com navegadores

  • Chrome: 35.
  • Edge: 79.
  • Firefox: 41.
  • Safari: 10.

Origem

var font = new FontFace("Awesome Font", "url(/fonts/awesome.woff2)", {
  style: 'normal', unicodeRange: 'U+000-5FF', weight: '400'
});

// don't wait for the render tree, initiate an immediate fetch!
font.load().then(function() {
  // apply the font (which may re-render text and cause a page reflow)
  // after the font has finished downloading
  document.fonts.add(font);
  document.body.style.fontFamily = "Awesome Font, serif";

  // OR... by default the content is hidden,
  // and it's rendered after the font is available
  var content = document.getElementById("content");
  content.style.visibility = "visible";

  // OR... apply your own render strategy here...
});

Além disso, como você pode verificar o status da fonte (usando o método check()) e acompanhar o andamento do download, você também pode definir uma estratégia personalizada para renderizar texto nas páginas:

  • É possível retardar toda a renderização de texto até que a fonte esteja disponível.
  • É possível implementar um tempo limite personalizado para cada fonte.
  • É possível usar a fonte de fallback para desbloquear a renderização e injetar um novo estilo que usará a fonte desejada depois que ela ficar disponível.

O melhor de tudo é que você também pode combinar as estratégias acima em conteúdos diferentes da página. Por exemplo, atrasar a renderização em algumas seções até que a fonte esteja disponível, usar uma fonte de fallback e renderizar novamente após o download da fonte.

O armazenamento em cache adequado é obrigatório

Normalmente, os recursos de fonte são estáticos e raramente atualizados. Portanto, são ideais para uma expiração longa de max-age. Especifique um cabeçalho ETag condicional e uma política ideal de Cache-Control para todos os recursos de fonte.

Se o aplicativo da Web usa um service worker, a maioria dos casos de uso exige a exibição de recursos de fonte com uma estratégia que prioriza o cache.

Não armazene fontes usando localStorage ou IndexedDB. Cada um deles tem seus próprios problemas de desempenho. O cache HTTP do navegador oferece o melhor e mais robusto mecanismo para fornecer recursos de fonte ao navegador.

Lista de verificação de carregamento de WebFonts

  • Personalize o carregamento e a renderização de fontes usando <link rel="preload">, font-display ou a Font Loading API:o comportamento padrão de carregamento lento pode resultar em atraso na renderização de texto. Esses recursos de plataforma da Web permitem modificar esse comportamento para determinadas fontes e especificar estratégias personalizadas de renderização e tempo limite para conteúdos diferentes na página.
  • Especifique políticas de revalidação e de armazenamento em cache ideal:as fontes são recursos estáticos, raramente atualizados. Verifique se os servidores fornecem um carimbo de data/hora de max-age longo e um token de revalidação para possibilitar a reutilização eficiente de fontes entre páginas distintas. Ao usar um worker de serviço, uma estratégia que prioriza o cache é apropriada.

Testes automatizados para o comportamento de carregamento de WebFont com o Lighthouse

O Lighthouse pode ajudar a automatizar o processo de garantir que você está seguindo as práticas recomendadas de otimização de fontes da Web.

As auditorias a seguir podem ajudar a garantir que suas páginas continuem seguindo as práticas recomendadas de otimização de fontes da Web ao longo do tempo: