Minimiser les téléchargements de fontes

Optimiser les fontes est un exercice difficile sur les sites d'envergure. Il existe une solution simple à mettre en œuvre, même si seuls certains navigateurs la prennent en charge.

Traduit depuis l’article Minimizing Font Downloads de Jake Archibald.


Toutes les traductions hébergées


Les fontes peuvent peser lourd

Très lourd. Ça peut aller de 70Ko à plusieurs méga-octers (compressés évidemment, car pourquoi s’en passer ?). Vous voulez du gras ? Eh bien, il suffit de doubler la taille. Des italiques ? Allez, on triple. Gras et italique ? On quadruple. C’est un sujet critique si ces fontes bloquent l'affichage du contenu principal, ce qui est souvent le cas.

Utiliser des sous-ensembles de la fonte permet de gagner pas mal de place en retirant tous les caractères dont vous n'avez pas besoin. Ça permet généralement de ramener la fonte sous les 50Ko.

Mais quels caractères conserver ? C'est assez difficile à déterminer si votre site a beaucoup de contenu, ou si les utilisateurs peuvent y créer du contenu. Si des caractères hors du sous-ensemble sont utilisés, ils auront recours à une police de substitution, ce qui peut être super moche.

Cohérent
Remarquez comme le « é » utilise une fonte différente du « e »

Vous pouvez soit tolérer cette laideur occasionnelle, soit être conservateurs dans vos sous-ensembles, ce qui vous ramène à des téléchargements lourds de fonte.

Mais il existe une meilleure solution !

Laissez tout bêtement le navigateur s'en occuper

Déterminez à la louche les caractères employés par la majorité de vos pages, faites un sous-ensemble, puis créez une autre ressource contenant les caractères additionnels :

/* Petit sous-ensemble, graisse = normal */
@font-face {
  font-family: whatever;
  src: url('reg-subset.woff') format('woff');
  unicode-range: U+0-A0;
  font-weight: normal;
}
/* Grand sous-ensemble, graisse = normal */
@font-face {
  font-family: whatever;
  src: url('reg-extended.woff') format('woff');
  unicode-range: U+A0-FFFF;
  font-weight: normal;
}
/* Petit sous-ensemble, graisse = gras */
@font-face {
  font-family: whatever;
  src: url('bold-subset.woff') format('woff');
  unicode-range: U+0-A0;
  font-weight: bold;
}
/* Grand sous-ensemble, graisse = gras */
@font-face {
  font-family: whatever;
  src: url('bold-extended.woff') format('woff');
  unicode-range: U+A0-FFFF;
  font-weight: bold;
}
/* Et utilisons la police : */
p {
  font-family: whatever, serif;
}

Le code ci-dessus contient de multiples définitions de fontes pour la même police, mais avec des graisses (font-weight) et sous-ensembles (unicode-range) distinctes. L'intervalle unicode U+0-A0 recouvre les glyphes basiques de lettres, nombres et ponctuations. Le navigateur sait ainsi qu'un glyphe « e » gras est disponible dans bold-subset.woff, alors qu'un « é » de graisse normale sera dans reg-extended.woff.

Un navigateur peut choisir intelligemment à l'aide de ces infos pour ne télécharger que le minimum requis pour afficher la page. Si la page utilise des caractères hors de ce sous-ensemble, la fonte supplémentaire est téléchargée en parallèle.

Cela ne vous dispense pas de fournir une fonte de substitution adaptée au cas où la vôtre ne peut pas être téléchargée à temps, ou si le navigateur n'en comprend pas le format.

Demo

Voyez plutôt.

Idéalement, le navigateur ne devrait télécharger au départ que la ressource normale pour le sous-ensemble. Mais dès que vous éditez le texte pour inclure, par exemple, « ö », le navigateur va télécharger la fonte supplémentaire.

Prise en charge par les navigateurs

OK, à présent les mauvaises nouvelles :

  • Safari : télécharge toutes les fontes
  • Internet Explorer : télécharge également toutes les fontes
  • Firefox : ne télécharge qu’une fonte, mais pas la bonne, ce qui laisse tout pété
  • Chrome : s’y prend bien, et ne télécharge au départ que la fonte normale du sous-ensemble
  • Opera : pareil que Chrome

C’est vraiment dommage pour IE et Safari, qui se retrouvent à télécharger 300Ko au lieu de 30Ko dans cet exemple. C'est encore bien pire si on rajoute de l'italique et du gras-italique, car IE et Safari les téléchargeront aussi, même si nous ne nous en servons pas.

À quoi il joue, Firefox ?

Firefox affiche ça mal

Firefox gère bien le font-weight, il ne télécharge que ce que la page utilise, malheureusement il ignore le unicode-range. La déclaration de fonte « reg-extended » écrase celle en « reg-subset », mais seulement grâce à l'ordre du code source. « reg-extended » est utilisée pour afficher la page, mais elle ne contient pas tous les caractères, alors on utilise une fonte de substitution. Naturellement, « sans-serif » aurait fait une substitution plus acceptable ici, mais je voulais mettre le problème bien en évidence.

Et s'il s'agit justement de la fonte étendue, comment se fait-il que la plupart des caractères soient affichés correctement ? On ne s'attend pas à ce que « o » fasse partie de l'ensemble étendu, et pourtant il y figure. Pour des raisons d'efficacité de stockage, au sein de la fonte, ö est une combinaison des glyphes o et ¨. Même si nous ne voulions pas conserver le « o » dans la fonte étendue, il y figure car d'autres glyphes en dépendent.

La théorie de réutilisation des glyphes selon Einstein

Aucun glyphe ne réutilise « F » ou « b », et du coup ils ne figurent pas dans la fonte étendue.

Firefox ne prête aucune attention au unicode-range. Tout en fournissant des informations pour les téléchargements, unicode-range détermine quels caractères le navigateur va utiliser dans la fonte, même si elle en contient d'autres.

On peut contourner le problème avec Firefox en incluant tous les glyphes dans les fontes listées en dernier dans vos sous-ensembles (« reg-extended » et « bold-extended » dans notre cas), ou en séparant les sous-ensembles en différentes familles de fontes :

/* Petit sous-ensemble, graisse = normal */
@font-face {
  font-family: whatever;
  src: url('reg-subset.woff') format('woff');
  unicode-range: U+0-A0;
  font-weight: normal;
}
/* Grand sous-ensemble, graisse = normal */
@font-face {
  font-family: whatever-extended;
  src: url('reg-extended.woff') format('woff');
  unicode-range: U+A0-FFFF;
  font-weight: normal;
}
/* Et utilisons la police : */
p {
  font-family: whatever, whatever-extended, serif;
}

Voici une démo de ça. Firefox télécharge quand même les deux fontes, qu'on en ait besoin ou non, mais au moins l'affichage est correct.

Exigez que ça soit corrigé !

Quand ça marche, c'est une super fonctionnalité, surtout pour les sites qui gèrent une variété de langues, qui autorisent leurs utilisateurs à ajouter leur propre contenu, ou simplement qui veulent télécharger cette fonte avec la super perluette de temps en temps. Si vous trouvez ça utile, alors dites-le aux créateurs des navigateurs (en incluant votre cas d'utilisation) :

Et entre-temps

Si vous servez déjà une fonte lourde, réfléchissez à la découper en fichiers multiples avec des unicode-range distincts. Utilisez à chaque fois une font-family distincte pour contourner le problème de Firefox.

IE, Firefox et Safari téléchargeront plus que ce dont ils ont besoin, mais seulement l'équivalent du gros fichier de fonte que vous aviez avant. Les utilisateurs de Chrome et Opera bénéficieront d'une expérience plus rapide, et avec un peu de chance les autres navigateurs suivront.

À lire sur ce sujet

  • WOFF2 - pris en charge par Chrome et Opera, réduit la taille des fichiers de fonte d'environ 20% supplémentaires