Mais opções de fontes variáveis para a fonte da IU do sistema macOS no Chromium 83

Catalina traz uma nova fonte de sistema de variáveis unificada para macOS.

A seção "system-ui" da especificação do nível 4 do módulo de fontes CSS define uma palavra-chave de fonte system-ui que permite que os desenvolvedores usem a fonte do sistema operacional padrão integrada, otimizada, localizada, de altíssima qualidade e sem necessidade de download diretamente nos sites e apps.

body {
  font-family: system-ui;
}

Essa escolha de tipografia é semelhante a "usar a fonte padrão do sistema para a localidade atual do usuário".

No macOS, a fonte system-ui é San Francisco, uma fonte que uma equipe de design avaliou, testou e... atualizou recentemente. Primeiro, vamos falar sobre os novos recursos interessantes de fontes variáveis na Catalina e depois sobre alguns bugs e como os engenheiros do Chromium os resolveram.

Esta postagem pressupõe que você já conhece as fontes variáveis. Caso contrário, confira Introdução a fontes variáveis na Web e o vídeo abaixo.

Compatibilidade com navegadores

No momento da publicação deste artigo, o system-ui tem suporte do Chromium (desde a versão 56), do Edge (desde a versão 79), do Safari (desde a versão 11) e do Firefox (desde a versão 43), mas com a palavra-chave -apple-system. Consulte Posso usar fontes variáveis? para conferir atualizações.

Novos poderes

As novas funcionalidades que o Catalina trouxe para a fonte do sistema agora estão disponíveis para desenvolvedores da Web a partir do Chromium 83. A fonte system-ui agora tem mais configurações variáveis: dimensionamento óptico e dois ajustes de peso exclusivos:

Mojave
h1 {
  font-family: system-ui;
  font-weight: 700;
  font-variation-settings:
    'wght' 750
  ;
}
Catalina
h1 {
  font-family: system-ui;
  font-weight: 700;
  font-variation-settings:
    'wght' 750,
    'opsz' 20,
    'GRAD' 400,
    'YAXS' 400
  ;
}

No Mojave, system-ui é uma fonte variável com apenas configurações wght. Já o system-ui no Catalina é uma fonte variável com as configurações wght, opsz, GRAD e YAXS.

Parece que há algumas oportunidades interessantes de design de melhoria progressiva. Se quiser, aprofunde-se nas sutilezas da fonte do sistema.

wght

Aceita um peso de fonte entre 0 e 900 e é aplicado igualmente a todos os caracteres.

/* 0-900 */
font-variation-settings: 'wght' 750;

opsz

O dimensionamento óptico é semelhante ao ajuste de espaçamento entre letras, mas a espaçagem é feita pelo olho humano, e não pela matemática. Um valor de 19 ou menos é para o espaçamento do texto e do corpo, enquanto 20 ou superior é destinado ao espaçamento de cabeçalhos e títulos de exibição.

/* 19 or 20 */
font-variation-settings: 'opsz' 20;

GRAD

Semelhante ao peso, mas sem tocar no espaçamento horizontal. Ele aceita valores entre 400 e 1000.

/* 400-1000 */
font-variation-settings: 'GRAD' 500;

YAXS

Estica o glifo verticalmente. Ele aceita valores entre 400 e 1000.

/* 400-1000 */
font-variation-settings: 'YAXS' 500;

Combinar as opções

Com algumas linhas de CSS, podemos ajustar as configurações da fonte para um negrito de nossa escolha ou testar outras combinações interessantes:

font-weight: 700;
font-weight: bold;
font-variation-settings: 'wght' 750, 'YAXS' 600, 'GRAD' 500, 'opsz' 20;

E assim, os usuários do Chromium no macOS vão notar o peso de 750 personalizado e atualizado com alguns outros ajustes divertidos 👍

Playground

Clique em Remix to Edit no Glitch abaixo para gerar uma cópia editável e depois edite as novas opções de font-variation-settings para conferir como isso afeta sua fonte. Lembre-se de que esse Glitch só vai funcionar se você estiver usando um dispositivo macOS Catalina.

O macOS 10.15 adicionou novos recursos à fonte do sistema e, no macOS 10.15, um bug system-ui complicado foi registrado no rastreador de bugs do Chromium. Será que eles são parentes?

Apêndice: a regressão system-ui

Esta história começa com um bug diferente: #1005969. Isso foi relatado no macOS 10.15 porque o espaçamento da fonte system-ui parecia estreito e apertado.

Uma comparação de dois parágrafos de uma página de grupo do Facebook. À esquerda está o Chrome e à direita está o Safari. O Chrome tem um espaçamento sutil, mas um pouco mais apertado
Chrome à esquerda (rastreamento mais apertado), Safari à direita (melhor espaçamento óptico)

Contexto

Você já notou no macOS 10.14 como seus parágrafos ou cabeçalhos são "ajustados" para uma fonte de aparência diferente quando o tamanho aumenta ou diminui?

No Mojave (macOS 10.14), a fonte system-ui alternava entre duas fontes, dependendo do tamanho da fonte de destino. Quando o texto estava abaixo de 20px, o macOS usava o "Texto San Francisco". Quando o texto era 20px ou mais, o macOS usava "San Francisco Display". O dimensionamento óptico foi criado de forma estática em duas fontes separadas.

Catalina (macOS 10.15) enviou uma nova fonte de variável unificada para São Francisco. Não é mais necessário gerenciar "Texto" e "Exibição". Ele também ganhou a nova configuração de variação opsz descrita anteriormente.

h1 {
  font-variation-settings: 'opsz' 20;
}

Infelizmente, o valor padrão de opsz na nova fonte Catalina é 20, e os engenheiros do Chromium não estavam preparados para aplicar opsz à fonte do sistema. Isso fez com que tamanhos menores aparecessem muito estreitos.

Para corrigir isso, o Chromium precisava aplicar a opsz corretamente à fonte do sistema. Isso levou à correção do Problema 1005969. Vitória! Ou foi…?

Ainda não terminou

Por isso, a situação ficou complicada: o Chromium aplicou opsz, mas algo não parecia certo. As fontes do sistema no Mac têm uma tabela de fontes adicional chamada trak, que ajusta o espaçamento horizontal. Enquanto trabalhavam na correção, os engenheiros do Chromium notaram que, no macOS, ao extrair métricas horizontais de um objeto CTFontRef, as métricas trak já estavam sendo consideradas nos resultados das métricas. A biblioteca de modelagem do Chromium HarfBuzz precisa de métricas em que os valores trak ainda não foram considerados.

Uma exibição de system-ui e todas as variações e pesos de fonte em uma lista. Metade deles não tem diferenças de peso aplicadas.
Esquerda: espessura de negrito aplicada aos tamanhos de fonte 19 e anteriores. Certo: os tamanhos de fonte 20 e acima perdem o estilo em negrito

Internamente, a Skia (a biblioteca gráfica, não o tipo de letra com o mesmo nome) usa a classe CGFontRef de CoreGraphics e a classe CTFontRef de CoreText. Devido às conversões internas necessárias entre esses objetos (usadas para manter a compatibilidade com versões anteriores e acessar as APIs necessárias em ambas as classes), o Skia perderia informações de peso em determinadas circunstâncias, e as fontes em negrito deixariam de funcionar. Isso foi rastreado no Problema 1057654.

O Skia ainda precisa oferecer suporte ao macOS 10.11 porque o Chromium ainda oferece suporte a ele. Na versão 10.11, as fontes "San Francisco Text" e "San Francisco Display" nem eram fontes variáveis. Em vez disso, cada uma era uma família de fontes separadas para cada peso disponível. Em algum momento, os IDs dos glifos ficaram dessincronizados. Assim, se o Skia forçar a formatação de texto (converter texto em glifos que podem ser desenhados) com "San Francisco Text", ele será exibido como caracteres sem sentido se for desenhado com "San Francisco Display", e vice-versa. E mesmo que Skia tenha pedido um tamanho diferente, o macOS pode trocar de tamanho. Deve ser possível usar sempre uma das fontes e apenas dimensioná-la (usando uma matriz para aumentar o tamanho em vez de pedir um tamanho maior), mas o CoreText tem um problema em que não dimensiona os glifos sbix (emoji colorido) para cima (apenas para baixo). É um pouco mais complexo do que isso. Na verdade, o CoreText parece limitar a extensão vertical após a aplicação da matriz, o que parece estar relacionado à impossibilidade de desenhar emojis em ângulos de 45 graus. De qualquer forma, se você quiser que seus emojis sejam exibidos em tamanho grande, será necessário fazer uma cópia da fonte para ter uma versão grande.

Para criar cópias de objetos CTFont em tamanhos diferentes internamente, garantindo que os mesmos dados de fonte sejam usados, o Chromium retirou o CGFont do CTFont e criou um novo CTFont a partir do CGFont. Os objetos CGFont são independentes do tamanho, a troca mágica acontece no nível CoreText. Isso funcionou bem até a versão 10.154. Na 10.15, essa viagem de ida e volta acabou perdendo muitas informações, resultando no problema de peso. O Flutter notou o problema de peso e uma correção alternativa para redimensionamento foi feita para criar o novo CTFont diretamente do CTFont original, controlando o tamanho óptico diretamente usando um atributo antigo, mas não documentado, em CoreText. Isso mantém tudo funcionando na versão 10.11 e corrige outros problemas, como definir explicitamente o tamanho óptico para o valor padrão.

No entanto, isso preserva mais a CoreText "mágica" na fonte. Um deles parece ser que ele ainda ajusta os avanços do glifo de alguma maneira diferente de apenas a tabela trak (a aplicação da qual o Chromium já estava tentando suprimir por meio de outro atributo não documentado).

CGFont não faz essa "magia", então talvez o Chromium possa tirar o CGFont do CTFont e usá-lo para receber avanços? Infelizmente, isso não funciona porque o CoreText também mexe com fontes de outras maneiras. Por exemplo, ele aumenta um pouco o tamanho de emojis pequenos, aumentando um pouco o tamanho deles. O CGFont não sabe disso, então você acaba com emojis baseados em sbix muito próximos uns dos outros, porque você está medindo em um tamanho, mas o CoreText os desenha maiores. O Chromium quer que a CTFont avance, mas quer que ela não seja rastreada e, de preferência, sem nenhuma confusão.

Como a correção do problema de espaçamento exigia um conjunto de correções interligadas do Blink e do Skia, os engenheiros do Chromium não podiam "apenas reverter" para corrigir o problema. Os engenheiros do Chromium também tentaram usar uma flag de build diferente para alterar um caminho de código relacionado a fontes no Skia, o que corrigiu o problema com fontes em negrito, mas regrediu o problema de espaçamento.

A correção

No final, é claro que o Chromium queria corrigir as duas coisas. O Chromium agora usa as funções de métricas de fonte OpenType integradas do HarfBuzz para extrair métricas horizontais diretamente dos dados binários nas tabelas de fontes do sistema. Com isso, o Chromium está contornando CoreText e Skia quando a fonte tem uma tabela trak (exceto quando é a fonte emoji).

Uma exibição da IU do sistema e da espessura da fonte e das variações em uma lista. A metade que não estava funcionando agora está ótima.

Enquanto isso, ainda há o Problema 10123 do Skia para corrigir a correção totalmente no Skia e voltar a usar o Skia para recuperar as métricas de fonte do sistema a partir dele, em vez da correção atual que passa por HarfBuzz.