Como atualizamos a web fonte dos PWAs do QuintoAndar
Trabalho com web há dez anos e nesse período já desenvolvi dezenas de sites e aplicações com diferentes tipos de fonte. Há uns três meses, meu time decidiu que iria trabalhar em fundações do design system do QuintoAndar e o primeiro passo seria usarmos uma fonte proprietária. Até aí tudo bem. Eu achava que precisaria apenas alterar a propriedade font-family
dos projetos da empresa e carregar os assets da nova fonte.
FOUT, FOFT, preload, variable font, e particularidades da propriedade font-display
do CSS foram alguns dos termos que surgiram assim que comecei a estudar. Uma coisa ficou bem clara: eu precisava reciclar meu conhecimento em relação a como usar fontes na web.
Vários PWAs, um design system e web performance
O QuintoAndar tem como objetivo ser a principal escolha para as pessoas quando o assunto é moradia. Para isso funcionar, temos aplicativos para diferentes tipos de usuários, como proprietários, inquilinos, corretores e fotógrafos. Hoje temos mais de vinte e oito PWAs (e contando).
A performance dessas aplicações é um requisito importante para o nosso negócio, uma vez que sempre buscamos fazer entregas que tenham uma experiência rápida para os usuários. E falando em entrega, temos um design system que está sendo desenvolvido há quase dois anos, e já está espalhado pelas aplicações.
Esse era nosso contexto, agora vamos às tecnologias.
Entregando fontes e estilos globais
Usamos CSS-in-JS para escrever nosso CSS, usando a biblioteca styled-components. Por meio dela, configuramos um tema, que nada mais é um objeto JavaScript com configurações de estilo através de nosso design system. Esse objeto é populado por um módulo JavaScript que é gerado pelo Style Dictionary, nossa ferramenta para gerenciar design tokens para diferentes plataformas — o QuintoAndar também tem apps nativos para iOS (Swift) e Android (Flutter).
Na prática, temos algo semelhante a isso:
import { elevations, palette, shape, typography } from '@quintoandar-design-system/tokens';export const theme = {
elevations,
palette,
shape,
typography,
};
Esse tema é utilizado pelas aplicações através do provider de nosso design system.
A escala tipográfica foi atualizada, assim como o peso e tamanho das fontes. Todas essas configurações foram feitas através de nosso pacote de tokens.
Para entregar o CSS com o @font-face
, criamos uma biblioteca que entrega uma folha de estilo com os arquivos de fonte. Preferimos fazer dessa forma por dois motivos:
- Aplicações e sites que não usam React podem instalar a fonte apenas usando CSS;
- Self-host fonte é a melhor opção para entrega. Atualmente ferramentas de bundle como webpack possuem otimizações para essa técnica.
Além disso, há estilos globais necessários para a família da fonte funcionar, como estilo para elemento body
. Para isso, criamos um componente React chamado <GlobalFontStyles/>
, que é responsável por prover esse CSS.
No final, pra usar a fonte nossos desenvolvedores precisaram de dois passos:
- Atualizar a versão da biblioteca do design system;
- Instalar a biblioteca da fonte.
import '@quintoandar-typeface.css'; // CSS com font-face
import { GlobalFontStyle } from '@quintoandar-design-systen/globals'; // Estilos globaisconst App = (props) => {
return (
<>
<GlobalFontStyle />
</>
);
};
Carregando e renderizando fontes de uma forma moderna
Como comentei no início do texto, meu conhecimento em relação a fonte se limitava a @font-face
e as propriedades de fonte como font-family
e font-size
. Mas uma das primeiras descobertas em relação a performance foi sobre Variable Fonts.
Variable Fonts
Anteriormente precisávamos de um arquivo para cada estilo de fonte. Se usássemos três pesos diferentes, o usuário precisaria baixar três arquivos de fonte diferentes. Já uma variable font agrupa todos os estilos de fonte em um único arquivo. Veja o exemplo abaixo usando a variable font da famosa Roboto:
Para configurar esse tipo de fonte também usamos a propriedade @font-face
, com a diferença que usamos woff2 supports variations
para o format()
:
@supports (font-variation-settings: normal) {
@font-face {
font-family: 'Roboto Flex';
src: url('./fonts/RobotoFlex.woff2') format('woff2 supports variations'),
url('./fonts/RobotoFlex.woff2') format('truetype-variations');
font-weight: 100 1000;
font-stretch: 25% 151%;
}
}
A propriedade font-variation-settings
nos provê um controle das configurações disponíveis da variable font através das letter axes disponíveis para serem usadas. Por padrão, temos os valores wght
, wdth
, slnt
, ital
e opsz
, que respectivamente servem para customizar font-weight
, font-stretch
, font-style: oblique + angle
, font-style: italic
e font-optical-sizing
. Mas também podemos utilizar axes customizados que podem ser disponibilizados por quem desenvolveu a fonte. No nosso caso, temos uma variação da fonte para títulos, e através da propriedade font-variation-settings
controlamos qual família de fonte será usada:
/* QuintoAndarSans Body*/
body {
font-feature-settings: 'ss01' on;
}/* QuintoAndarSans Title*/
h1, h2, h3,
h4, h5, h6 {
font-feature-settings: 'ss01' off;
}
Na prática, variable fonts ajudam muito em performance. Mas além delas, para ajudar em melhores resultados de carregamento é interessante fazer preload dos assets usando <link rel="preload">
. Essa configuração irá fazer o request da fonte antes da construção do CSSOM.
Otimizando a forma de renderizar a fonte
A maioria dos navegadores modernos suportam a propriedade font-display
, que determina como a fonte será renderizada. Para entender os valores que essa propriedade recebe, precisamos saber o que é a font display timeline. Ela é divida em três períodos que determinam como a fonte será renderizada.
- Font block period: se a fonte não está disponível, isso não irá renderizar nada, e quando ela for baixada, ela aparecerá para o usuário.
- Font swap period: enquanto a fonte não for renderizada, a fonte de fallback será mostrada.
- Font failure period: é o momento que que a fonte não pode ser renderizada, e apenas o fallback é mostrado para o usuário.
No nosso caso, usamos font-display: swap
, que renderiza a fonte de fallback até que a fonte customizada esteja disponível. O efeito colateral dessa estratégia é que em casos que a fonte demora para baixar, ocorrerá o que chamam de "flash of unstyled text" (FOUT).
Desde a versão 83, o Google Chrome mudou a forma de como lida com o uso de font-display: optional
. Nas versões antigas e em outros navegadores isso irá causar "flash of invisible text" (FOIT), ou seja, não irá renderizar o conteúdo até que a fonte esteja disponível. Mas a combinação dessa propriedade CSS com o preload dos arquivos de fonte, o primeiro paint já virá com a fonte correta.
Algo extremamente recomendado para otimizar é cachear os arquivos por um longo período e servir as fontes através de service worker.
Conclusão
Quando comecei a trabalhar ainda tinham sites que eram desenvolvidos com Flash para usar fontes customizadas. Depois o CSS3 nos deu o font-face e revolucionou a forma com que trabalhávamos. As especificações de fonte evoluíram absurdamente nos últimos dez anos.
A web não parou de evoluir e essa foi uma das principais características que me fizeram escolhe-la como ferramenta de trabalho. Na verdade fui eu quem parou de acompanhá-la e essa foi uma das grandes lições que tive no último ano: nunca parar de evoluir com a web.
Quer trabalhar em um lugar onde você tem tempo de estudar e entregar produtos com qualidade? Quer trabalhar em um lugar com desafios em escala e muitas pessoas brilhantes pra te ajudar a resolver eles e aprender sobre? Vem pro QuintoAndar!