Fontes substitutas aprimoradas

Katie Hempenius
Katie Hempenius

Resumo

Este artigo é um mergulho profundo nos substitutos de fontes e nas APIs size-adjust, ascent-override, descent-override e line-gap-override. Essas APIs permitem usar fontes locais para criar fontes de substituição que correspondam exatamente ou de forma aproximada às dimensões de uma fonte da Web. Isso reduz ou elimina as mudanças de layout causadas pela troca de fontes.

Se você preferir pular a leitura deste artigo, confira algumas das ferramentas que podem ser usadas para começar a usar essas APIs imediatamente:

Ferramentas de framework:

  • @next/font: a partir do Next 13, o next/font usa automaticamente substituições de métrica de fonte e size-adjust para fornecer fallbacks de fonte correspondentes.
  • @nuxtjs/fontaine: a partir do Nuxt 3, é possível usar nuxt/fontaine para gerar e inserir automaticamente substitutos de fontes correspondentes nas folhas de estilo usadas pelo app Nuxt.

Ferramentas que não são de framework:

  • Fontaine: a Fontaine é uma biblioteca que gera e insere automaticamente substitutos de fonte que usam substituições de métrica de fonte.
  • Este repo contém as substituições de métrica de fonte para todas as fontes hospedadas pelo Google Fonts. Esses valores podem ser copiados e colados nas folhas de estilo.

Contexto

Uma fonte de fallback é um tipo de fonte usado quando o tipo de fonte principal ainda não foi carregado ou não tem os glifos necessários para renderizar o conteúdo da página. Por exemplo, o CSS abaixo indica que a família de fontes sans-serif deve ser usada como substituto para "Roboto".

font-family: "Roboto" , sans-serif;

As fontes de fallback podem ser usadas para renderizar textos mais rapidamente (ou seja, usando font-display: swap). Como resultado, o conteúdo da página fica legível e útil mais cedo. No entanto, historicamente, isso tem um custo de instabilidade do layout: as mudanças de layout geralmente ocorrem quando uma fonte de fallback é trocada pela fonte da Web. No entanto, as novas APIs discutidas abaixo podem reduzir ou eliminar esse problema, permitindo a criação de fontes de fallback que ocupam a mesma quantidade de espaço que a fonte da Web.

Melhorias nas fontes substitutas

Há duas abordagens possíveis para gerar substitutos de fontes "melhores". A abordagem mais simples usa apenas a API de substituição de métricas de fonte. A abordagem mais complicada (mas mais poderosa) usa a API de substituições de métricas de fonte e size-adjust. Neste artigo, explicamos as duas abordagens.

Como funciona a substituição da métrica de fonte

Introdução

As substituições de métrica de fonte oferecem uma maneira de substituir a ascensão, a descida e o espaçamento entre linhas de uma fonte:

  • O ascendente mede a distância mais longa que os glifos de uma fonte se estendem acima da linha de base.
  • A descida mede a distância mais longa que os glifos de uma fonte se estendem abaixo da linha de base.
  • O espaço entre linhas, também chamado de "leading", mede a distância entre linhas sucessivas de texto.

Diagrama que mostra a ascensão, a descida e o espaço entre linhas de uma fonte.

As substituições de métrica de fonte podem ser usadas para substituir a ascensão, a descida e o espaçamento entre linhas de uma fonte de fallback para corresponder à ascensão, a descida e o espaçamento entre linhas da fonte da Web. Como resultado, a fonte da Web e a fonte substituta ajustada sempre terão as mesmas dimensões verticais.

As substituições de métrica da fonte são usadas em uma folha de estilo como esta:

body {
    font-family: Poppins, "fallback for poppins";
}

@font-face {
    font-family: "fallback for poppins";
    src: local("Times New Roman");
    ascent-override: 105%;
    descent-override: 35%;
    line-gap-override: 10%;
}

As ferramentas listadas no início deste artigo podem gerar os valores corretos de substituição de métrica de fonte. No entanto, você também pode calcular esses valores.

Como calcular substituições de métricas de fonte

As equações a seguir geram as substituições de métrica de fonte para uma determinada fonte da Web. Os valores de substituições de métricas de fonte precisam ser escritos como porcentagens (por exemplo, 105%) em vez de decimais.

ascent-override = ascent/unitsPerEm
descent-override = descent/unitsPerEm
line-gap-override = line-gap/unitsPerEm

Por exemplo, estas são as substituições de métrica de fonte para a fonte Poppins:

/*
Poppins font metrics:
ascent = 1050
descent = 350
line-gap = 100
UPM: 1000
*/

ascent-override: 105%;  /* = 1050/1000 */
descent-override: 35%;  /* = 350/1000 */
line-gap-override: 10%; /* = 100/1000 */

Os valores de ascent, descent, line-gap e unitsPerEm vêm dos metadados da fonte da Web. A próxima seção deste artigo explica como conseguir esses valores.

Leitura de tabelas de fontes

Os metadados de uma fonte (especificamente, as tabelas de fontes) contêm todas as informações necessárias para calcular as substituições de métricas de fonte.

Captura de tela da caixa de diálogo "Font Information" no FontForge. A caixa de diálogo mostra métricas de fonte, como "Ascensão tipográfica", "Descida tipográfica" e "Espaçamento entre linhas tipográficas".
Como usar o FontForge para conferir os metadados da fonte

Confira algumas ferramentas que podem ser usadas para ler os metadados de uma fonte:

  • O fontkit é um mecanismo de fontes criado para Node.js. Este snippet de código mostra como usar o FontKit para calcular substituições de métricas de fonte.
  • Capsize é uma biblioteca de dimensionamento e layout de fontes. O Capsize fornece uma API para receber informações sobre várias métricas de fonte.
  • fontdrop.info é um site que permite visualizar tabelas de fontes e outras informações relacionadas a fontes no navegador.
  • O Font Forge é um editor de fontes para computador muito conhecido. Para conferir ascent, descent e line-gap: abra a caixa de diálogo Font Info, selecione o menu OS/2 e a guia Metrics. Para conferir UPM, abra a caixa de diálogo Font Info e selecione o menu General.

Como entender as tabelas de fontes

Você pode notar que conceitos como "ascensão" são referidos por várias métricas. Por exemplo, há as métricas hheaAscent, typoAscent e winAscent. Isso é resultado de diferentes sistemas operacionais que usam abordagens diferentes para renderização de fontes: os programas em dispositivos OSX geralmente usam métricas de fonte hhea*, enquanto os programas em dispositivos Windows geralmente usam métricas de fonte typo* (também chamadas de sTypo*) ou win*.

Dependendo da fonte, do navegador e do sistema operacional, uma fonte será renderizada usando as métricas hhea, typo ou win.

Mac Windows
Chromium Usa métricas da tabela "hhea". Usa métricas da tabela "typo" se "USE_TYPO_METRICS" tiver sido definido. Caso contrário, vai usar métricas da tabela "win".
Firefox Usa métricas da tabela "typo" se "USE_TYPO_METRICS" tiver sido definido. Caso contrário, vai usar métricas da tabela "hhea". Usa métricas da tabela "typo" se "USE_TYPO_METRICS" tiver sido definido. Caso contrário, vai usar métricas da tabela "win".
Safari Usa métricas da tabela "hhea". Usa métricas da tabela "typo" se "USE_TYPO_METRICS" tiver sido definido. Caso contrário, vai usar métricas da tabela "win".

Para mais informações sobre como as métricas de fonte funcionam em vários sistemas operacionais, consulte este artigo sobre métricas verticais.

Compatibilidade com vários dispositivos

Para a maioria das fontes (por exemplo, cerca de 90% das fontes hospedadas pelo Google Fonts), as substituições de métricas de fonte podem ser usadas com segurança sem conhecer o sistema operacional do usuário. Em outras palavras, para essas fontes, os valores de ascent-override, descent-override e linegap-override permanecem exatamente os mesmos, independentemente de as métricas hhea, typo ou win serem aplicadas. Este repo fornece informações sobre quais fontes se aplicam e quais não se aplicam.

Se você estiver usando uma fonte que exige o uso de conjuntos separados de substituições de métricas de fonte para dispositivos OSX e Windows, o uso de substituições de métricas de fonte e size-adjust só é recomendado se você puder variar as folhas de estilo com base no sistema operacional do usuário.

Como usar substituições de métricas de fonte

Como as substituições de métrica de fonte são calculadas usando medições provenientes dos metadados da fonte da Web (e não da fonte de substituição), elas permanecem as mesmas, independentemente de qual fonte for usada como padrão. Exemplo:

body {
  font-family: "Poppins", "fallback for Poppins", "another fallback for Poppins";
}

@font-face {
  font-family: "fallback for Poppins";
  src: local("Arial");
  ascent-override: 105%;
  descent-override: 35%;
  line-gap-override: 10%;
}

@font-face {
  font-family: "another fallback for Poppins";
  src: local("Roboto");
  ascent-override: 105%;
  descent-override: 35%;
  line-gap-override: 10%;
}

Como o ajuste de tamanho funciona

Introdução

O descritor CSS size-adjust dimensiona proporcionalmente a largura e a altura dos glifos da fonte. Por exemplo, size-adjust: 200% dimensiona os glifos da fonte para o dobro do tamanho original. size-adjust: 50% dimensiona os glifos da fonte para metade do tamanho original.

Diagrama mostrando os resultados do uso de "size-adjust: 50%" e "size-adjust: 200%".

Por si só, size-adjust tem aplicações limitadas para melhorar as fontes de fallback: na maioria dos casos, uma fonte de fallback precisa ser estreitada ou alargada um pouco (em vez de ser dimensionada proporcionalmente) para corresponder a uma fonte da Web. No entanto, a combinação de size-adjust com substituições de métrica de fonte permite que duas fontes sejam correspondentes horizontal e verticalmente.

Confira como size-adjust é usado em folhas de estilo:

@font-face {
  font-family: "fallback for poppins";
  src: local("Arial");
  size-adjust: 60.85099821%;
  ascent-override: 164.3358416%;
  descent-override: 57.51754455%;
  line-gap-override: 16.43358416%;
}

Devido à forma como size-adjust é calculado (explicado na próxima seção), o valor de size-adjust (e as substituições de métrica de fonte correspondentes) muda dependendo da fonte de fallback usada:

body {
  font-family: "Poppins", "fallback for Poppins", "another fallback for Poppins";
}

@font-face {
  font-family: poppins-fallback;
  src: local("Arial");
  size-adjust: 60.85099821%;
  ascent-override: 164.3358416%;
  descent-override: 57.51754455%;
  line-gap-override: 16.43358416%;
}

@font-face {
  font-family: poppins-fallback-android;
  src: local("Roboto");
  size-adjust: 55.5193474%:
  ascent-override: 180.1173909%;
  descent-override: 63.04108683%;
  line-gap-override: 18.01173909%;
}

Como calcular substituições de métricas de tamanho e fonte

Estas são as equações para calcular a substituição de size-adjust e a métrica da fonte:

size-adjust = avgCharacterWidth of web font / avgCharacterWidth of fallback font
ascent-override = web font ascent / (web font UPM * size-adjust)
descent-override = web font descent / (web font UPM * size-adjust)
line-gap-override = web font line-gap / (web font UPM * size-adjust)

A maioria dessas entradas (ou seja, ascensão, descida e espaçamento entre linhas) pode ser lida diretamente dos metadados da fonte da Web. No entanto, avgCharacterWidth precisa ser aproximado.

Aproximação da largura média de caracteres

Em geral, a largura média dos caracteres só pode ser aproximada, mas há alguns cenários em que isso pode ser calculado exatamente, por exemplo, ao usar uma fonte monoespaçada ou quando o conteúdo de uma string de texto é conhecido com antecedência.

Um exemplo de abordagem simplista para calcular avgCharacterWidth é usar a largura média de todos os caracteres [a-z\s].

 Gráfico comparando a largura de glifos individuais do Roboto [a-zs].
Largura dos glifos Roboto

No entanto, dar peso igual a todos os caracteres provavelmente vai subestimar a largura das letras usadas com frequência (por exemplo, e) e superestimar a largura das letras usadas com pouca frequência (por exemplo, z).

Uma abordagem mais complexa que melhora a precisão é considerar a frequência das letras e calcular a largura média ponderada pela frequência dos caracteres [a-z\s]. Este artigo é uma boa referência para a frequência de letras e o comprimento médio das palavras em textos em inglês.

Um gráfico mostrando a frequência de letras em inglês.
Frequência de letras em inglês

Como escolher uma abordagem

As duas abordagens discutidas neste artigo têm vantagens e desvantagens:

  • Usar substituições de métrica de fonte por conta própria é uma boa abordagem se você estiver começando a otimizar as fontes alternativas. Embora essa seja a abordagem mais simples, ela geralmente é poderosa o suficiente para reduzir significativamente a magnitude das mudanças de layout relacionadas à fonte.

  • Por outro lado, se você quiser mais precisão e estiver disposto a fazer um pouco mais de trabalho e testes, incorporar size-adjust é uma boa abordagem. Quando implementada corretamente, essa abordagem pode eliminar efetivamente as mudanças de layout relacionadas a fontes.

Como escolher fontes substitutas

As técnicas descritas neste artigo dependem de substituições de métricas de fonte e size-adjust para transformar fontes locais amplamente disponíveis, em vez de tentar encontrar uma fonte local que se aproxima da fonte da Web. Ao escolher fontes locais, é importante lembrar que poucas fontes têm disponibilidade local ampla e nenhuma única fonte vai existir em todos os dispositivos.

Arial é a fonte substituta recomendada para fontes sem serifa, e Times New Roman é a fonte substituta recomendada para fontes com serifa. No entanto, nenhuma dessas fontes está disponível no Android (Roboto é a única fonte do sistema no Android).

O exemplo abaixo usa três fontes de fallback para garantir a cobertura de dispositivos mais ampla: uma fonte de fallback para dispositivos Windows/Mac, uma para dispositivos Android e uma que usa uma família de fontes genérica.

body {
  font-family: "Poppins", poppins-fallback, poppins-fallback-android, sans-serif;
}

/*
Poppins font metrics:
- ascent = 1050
- descent = 350
- line-gap = 100
- UPM: 1000
AvgCharWidth:
- Poppins: 538.0103768
- Arial: 884.1438804
- Roboto: 969.0502537
*/

@font-face {
  font-family: poppins-fallback;
  src: local("Arial");
  size-adjust: 60.85099821%;
  ascent-override: 164.3358416%;
  descent-override: 57.51754455%;
  line-gap-override: 16.43358416%;
}

@font-face {
  font-family: poppins-fallback-android;
  src: local("Roboto");
  size-adjust: 55.5193474%:
  ascent-override: 180.1173909%;
  descent-override: 63.04108683%;
  line-gap-override: 18.01173909%;
}

Pedido de feedback

Entre em contato se tiver algum feedback sobre sua experiência usando substituições de métricas de fonte e size-adjust.