Optimiser le chargement des webfonts
lundi 31 juillet 2023
Nous voici de retour dans cette sĂ©rie dâarticles liĂ©s Ă la web performance. Cette semaine, je vous propose de se concentrer sur les polices dâĂ©criture. Câest souvent un Ă©lĂ©ment essentiel de la charte graphique de votre site web. Câest aussi un Ă©lĂ©ment qui peut ruiner vos performances sâil nâest pas bien gĂ©rĂ©.
Nous allons donc voir dans cet article les diffĂ©rentes configurations possibles et ce quâil est pertinent de gĂ©rer pour amĂ©liorer au maximum la performance ressentie par vos utilisateurices.
Si vous ressentez le besoin dâavoir plus dâaccompagnement dans votre entreprise pour mettre en place ces sujets, nâhĂ©sitez pas Ă me contacter par mail. Peut-ĂȘtre pouvons-nous travailler ensemble pour proposer la meilleure expĂ©rience Ă vos utilisateuricesâŻ?
Récapitulatif des articles de cette série :
- Pourquoi améliorer le LCP de vos pages�
- Analyser le comportement réseau pour améliorer FCP et LCP
- Optimiser les images sur le web : checklist des bonnes pratiques
- Optimiser le chargement des fonts (vous ĂȘtes ici)
- Optimiser la gestion des icĂŽnes
- Comment diagnostiquer et corriger du Cumulative Layout Shift (CLS)�
- Quelles techniques pour diminuer la quantité de JavaScript� (bientÎt)
- Quelles métriques suivre en dehors des Core Web Vitals� (bientÎt)
- Et plus encore đ«¶
PrĂ©requis : cet article se concentre sur lâoptimisations et les points dâattention sur la gestion des fonts. Si vous nâavez jamais installĂ© de web font ou que vous nâavez jamais vu de @font-face jusquâĂ maintenant, je vous conseille de commencer par suivre ce tutoriel utiliser une web font (EN).
Avez-vous vraiment besoin dâune fontâŻ?
Souvent, la premiĂšre considĂ©ration Ă avoir au sujet des performances est de savoir sâil est possible de faire moins. Est-ce que la police que vous utilisez est indispensableâŻ?
Vous pourriez par exemple envisager dâutiliser cette rĂšgle par dĂ©faut :
font-family: system-ui, sans-serif;
Source: Modern Font Stacks (dâautres styles disponibles)
Câest une façon de dire au site web : utilise juste la police par dĂ©faut du systĂšme. Ainsi, lâutilisateurice ne devrait pas ĂȘtre trop choqué·e par celle-ci puisque câest celle quâiel voit au quotidien dans son OS. Ce blog a longtemps utilisĂ© cette mĂ©thode. Mais ça ne reprĂ©sente que rarement la rĂ©alitĂ© dâun site web dâentreprise.
Bien souvent vous nâaurez pas en main les clĂ©s pour prendre cette dĂ©cision. Il sâagit plutĂŽt dâune considĂ©ration de marque : la police dâĂ©criture est un moyen efficace de vĂ©hiculer une Ă©motion et donc de se positionner.
Mais peut-ĂȘtre pouvez-vous faire pencher la balancer vers moins de fonts. Quand un·e designer·euse me demande combien de fonts utiliser pour le site, je rĂ©ponds gĂ©nĂ©ralement 2 fonts avec un grand maximum de 3, graisses incluses. Par exemple, sur ce blog, câest la font âAssistantâ qui utilise 3 graisses diffĂ©rentes (font-weight). Mais si jâavais eu une font pour les titres et une font pour les paragraphes, jâaurais poussĂ© pour que les titres aient toujours la mĂȘme graisse.
Rappels sur les bonnes pratiques réseau
Avant de rentrer dans le vif du sujet, je veux juste rappeler en quelques mots 2 bonnes pratiques que nous avions vu dans un des premiers articles de cette série Comment analyser la trace réseau de votre site� :
-
assurez vous que la font est hĂ©bergĂ©e sur le mĂȘme domaine que votre page HTML :
Sur une connexion classique, cela vous fera gagner facilement 100ms de temps de chargement. Mais sur des connexions plus ératiques, vous pouvez facilement considérer que cela vous fera gagner dans les 500ms. -
évitez les effets de cascade en ajoutant un
<link rel="preload">
Classiquement, câest le CSS qui indique Ă votre navigateur quâil faut tĂ©lĂ©charger une nouvelle font. Pour gagner en temps dâattente, vous pouvez lâindiquer dans votre HTML afin que la font soit tĂ©lĂ©chargĂ©e en parallĂšle de votre CSS.<head> <link rel="preload" as="font" type="font/woff2" href="/assets/fonts/ovo.woff2" crossorigin /> </head>
Ces premiĂšres bonnes pratiques pourront vous amener dans la bonne direction. Mais elles ne seront pas suffisantes.
Comment faire alors pour charger rapidement les fonts�
Comme Ă chaque fois en informatique, nous allons voir quâil nây a pas une maniĂšre unique de faire les choses. Il vous faudra donc choisir la bonne mĂ©thode en fonction de votre situation. Du plus simple au plus compliquĂ© nous verrons donc :
- utiliser une font unique
- utiliser plusieurs graisses de fonts grĂące aux Variable Fonts
- utiliser plusieurs fonts
Vous pouvez bien Ă©videmment aller directement aux sections qui vous intĂ©ressent. Sachez cependant que je rentre dans pas mal de dĂ©tails lors de la premiĂšre section. Si les notions de subset, de font-display ou de size-adjust vous sont Ă©trangĂšres ou ont besoin de rappels, nâhĂ©sitez donc pas Ă prendre le temps de la lire avant de passer aux suivantes.
Par ailleurs, si vous voulez un historique de comment on en est arrivĂ© lĂ , sachez que cet article par Zach Leatherman retrace les diffĂ©rentes techniques qui existent. Mon but ici est de vous proposer les mĂ©thodes qui vous seront utiles aujourdâhui avec le support des navigateurs qui sâest grandement amĂ©liorĂ©.
1. Utiliser une font unique
Admettons que la seule font que vous souhaitez utiliser est Ovo.
1.1. Récupérer le fichier de font
La premiĂšre Ă©tape va ĂȘtre de rĂ©cupĂ©rer la font et de la transformer dans le bon format. En effet, si vous tĂ©lĂ©charger la police directement depuis Google Font, vous la rĂ©cupĂ©rerez en TTF. Mais :
- le format le plus performant est WOFF 2.0 qui est supportĂ© par 96.4% des navigateurs aujourdâhui et peut vous faire Ă©conomiser 67% de taille de fichier (48KB -> 16KB)
- il y a des chances que vous nâutilisiez quâun nombre rĂ©duit de caractĂšres. Par exemple si votre site est en français, vous utiliserez âĂ©â et âĆâ, mais pas âĂâ par exemple. Cela nous fait gagner quelques KB de plus (16KB -> 12KB).
Pour appliquer ces changements, vous pouvez exécuter la commande suivante :
pyftsubset \
./static/fonts/Ovo-Regular.ttf \
--unicodes="U+20-5F, U+61-7A, U+7C, U+A0, U+A7, U+A9, U+AB, U+B2-B3, U+BB, U+C0, U+C2, U+C6-CB, U+CE-CF, U+D4, U+D9, U+DB-DC, U+E0, U+E2, U+E6-EB, U+EE-EF, U+F4, U+F9, U+FB-FC, U+FF, U+152-153, U+178, U+2B3, U+2E2, U+1D48-1D49, U+2010-2011, U+2013-2014, U+2019, U+201C-201D, U+2020-2021, U+2026, U+202F-2030, U+20AC, U+2212" \
--layout-features='*' \
--flavor=woff2 \
--output-file=./static/fonts/Ovo-critical.woff2
đĄ Pour installer
pyftsubset, vous pouvez exĂ©cuterpip3 install fonttools[woff,unicode].Si vous nâavez pas python sur votre machine, vous pouvez utiliser le petit Dockerfile que jâai moi-mĂȘme utiliser pour ce blog.
Cette commande va supprimer tous les caractĂšres qui ne sont pas dans la liste --unicodes. Vous pouvez dĂ©terminer cette liste en utilisant Character Table qui indique par langue quels caractĂšres utiliser. Celle que jâai utilisĂ© dans lâexemple ci-dessus est pour le Français. Comme vous pouvez le voir Ă la fin du tableau, certains caractĂšres ne font pas forcĂ©ment partie de notre quotidien : â , âĄ. NâhĂ©sitez donc pas Ă faire le tri par vous mĂȘme.
Si vous voulez une liste trÚs précise, vous pouvez récupérer la liste de votre site directement en utilisant glyphhanger. En CLI, il peut parcourir votre site pour en lister les caractÚres utiliser, se concentrer sur des sections critiques, etc.
Pour les autres options telles que --layout-features, nâhĂ©sitez pas Ă vous rĂ©fĂ©rer Ă lâarticle complet de Code Colibri.
đĄ Quand vous rĂ©cupĂ©rez les polices depuis Google Font, vous pourrez tomber sur des subset tout prĂȘts : latin, latin-ext, cyrillic, etc. GĂ©nĂ©ralement, latin est la version la plus proche de ce que vous voulez si vous opĂ©rez principalement en occident. Mais gardez en tĂȘte quâil y a quand mĂȘme plus de caractĂšres que nĂ©cessaire et donc quâil est pertinent de construire vous mĂȘme votre liste de caractĂšres (
--unicodes).
1.2 Référencer la font dans notre CSS
Maintenant que nous avons notre fichier optimisĂ©, nous allons pouvoir indiquer au navigateur quâune web font est disponible en CSS via @font-face :
@font-face {
font-family: 'Ovo';
font-display: fallback;
/* Penser Ă bien hĂ©berger la font sur le mĂȘme domaine que mon site */
src: url(/fonts/ovo.woff2) format('woff2');
/* RĂ©utiliser ici exactement la mĂȘme liste unicode que ci-dessus */
unicode-range: U+20-5F, U+61-7A, U+7C, U+A0, U+A7, U+A9, U+AB, U+B2-B3, U+BB, U+C0, U+C2, U+C6-CB,
U+CE-CF, U+D4, U+D9, U+DB-DC, U+E0, U+E2, U+E6-EB, U+EE-EF, U+F4, U+F9, U+FB-FC, U+FF,
U+152-153, U+178, U+2B3, U+2E2, U+1D48-1D49, U+2010-2011, U+2013-2014, U+2019, U+201C-201D,
U+2020-2021, U+2026, U+202F-2030, U+20AC, U+2212;
}
body {
font-family: 'Ovo', serif;
}
Plusieurs choses intéressantes à noter ici.
Je nâai indiquĂ© ni font-style ni font-weight dans @font-face. Ainsi, le navigateur utilise la font Ovo quand bien mĂȘme le fichier quâon a utilisĂ© ne fournit quâun style roman (font-style: normal; font-weight: normal). En effet, quand le navigateur va tomber sur du gras et/ou de lâitalique, il va alors faire de la Font Synthesis : il va inventer une graisse et/ou un style Ă partir du style roman. Ce ne sera pas parfait, mais ce sera souvent mieux que dâutiliser une typo complĂštement diffĂ©rente pour le gras/italique. Selon la font choisie, le rĂ©sultat pourra ĂȘtre dĂ©cevant, voire rĂ©dhibitoire. Dans ce cas lĂ vous devrez passer par une Variable Font ou plusieurs fonts.
Jâutilise la rĂšgle font-display: fallback. Cette ligne indique comment doit se comportement le navigateur pendant le chargement de la font. Notamment, comment est-ce que la font doit sâafficher si le HTML et le CSS ont fini de se charger mais que le navigateur nâa pas encore reçu le fichier ovo.woff2âŻ?
- si cela ne fait pas longtemps (< ~100ms), alors la typo nâest pas affichĂ©e (Flash Of Invisible Text (FOIT))
- si cela fait un peu longtemps (< ~3s), alors la premiĂšre typo disponible dans la
font-familysâaffiche (Flash Of Unstyled Text (FOUT)). - si cela fait longtemps (> ~3s), alors on abandonne le chargement de
ovo.woff2et on reste sur la typo de lâĂ©tape prĂ©cĂ©dente.
Câest un bon comportement par dĂ©faut parce que :
- Si la font est rapide Ă charger, on nâa pas de saut de texte au chargement des fonts
- Si la font met du temps à se charger, vos utilisateurices ne restent pas bloqué·e·s sur une page vide
- Si la font est vraiment trop lente, les personnes auront certainement commencé à lire le texte et seront au milieu de la page : pour éviter de perturber leur lecture, on évite de changer de font.
Dâautres mĂ©thodes existent dans font-display. Je nâentrerai pas dans le dĂ©tail, mais si vous dĂ©cidez de choisir autre chose que fallback, privilĂ©giez soit optional soit swap. Jamais auto ou block qui auront un effet dĂ©sastreux sur les connexions lentes.
1.3 Choisir des bons fallbacks
Dans la dĂ©finition de la font-family (font-family: 'Ovo', serif;), vous pouvez constater que jâai mis serif aprĂšs Ovo. Câest une Ă©tape importante dans la dĂ©finition de la font parce que vos utilisateurices verront cette font Ă un moment ou Ă un autre (dans un train, pendant leur voyage Ă la campagne ou juste parce que leur wifi a dĂ©cidĂ© dâĂȘtre particuliĂšrement lent).
Pourquoi serifâŻ? Pour avoir un style proche de la typo finale, tout en Ă©tant sĂ»r quâelle soit disponible. serif est adaptĂ© si la police finale a des petits pieds au bout des lettres (= empattements). Sinon, privilĂ©giez plutĂŽt sans-serif.
Mais on peut mieux faire.
Size-adjust
Notamment, une nouvelle mĂ©thode est en train dâarriver dans les navigateurs : size-adjust. Celle-ci est disponible sur 73% des navigateurs actuellement, on croise les doigts pour que ça arrive aussi sur Safari.
Ce size-adjust a pour but dâajuster la font de fallback pour quâelle se rapproche au maximum des espacements utilisĂ©s par la font finale. Ainsi, si la font de fallback est affichĂ©e puis remplacĂ©e par la font finale, on minimise les soucis de lecture.
Dans lâexemple ci-dessous, vous pouvez changer de tabs pour constater la diffĂ©rence que cela provoque :
- Si vous passez de âFallback sans size-adjustâ Ă âFont finaleâ, vous constaterez que vous aurez du mal Ă vous repĂ©rer : il vous faudra un petit temps avant de pouvoir reprendre votre lecture
- Si vous passez de âFallback avec size-adjustâ Ă âFont finaleâ, vous remarquerez un changement de graisse et de style, mais la diffĂ©rence est minime

Pour mettre en place ce size-adjust, vous aurez besoin de deux parties :
-
déclarer votre font de fallback
@font-face { font-family: 'Ovo-fallback'; size-adjust: 109.1%; ascent-override: 72%; src: local('Times New Roman'); unicode-range: U+20-5F, U+61-7A, U+7C, U+A0, U+A7, U+A9, U+AB, U+B2-B3, U+BB, U+C0, U+C2, U+C6-CB, U+CE-CF, U+D4, U+D9, U+DB-DC, U+E0, U+E2, U+E6-EB, U+EE-EF, U+F4, U+F9, U+FB-FC, U+FF, U+152-153, U+178, U+2B3, U+2E2, U+1D48-1D49, U+2010-2011, U+2013-2014, U+2019, U+201C-201D, U+2020-2021, U+2026, U+202F-2030, U+20AC, U+2212; } -
utiliser ce fallback dans votre déclaration de font-family
body { font-family: 'Ovo', 'Ovo-fallback', serif; }
Ces quelques lignes fonctionneront pour Ovo, mais je pense quâil y a quelques subtilitĂ©s Ă expliquer :
-
Pourquoi Times New Roman plutÎt que serif� Parce que chaque size-adjust va dépendre de la typo utilisée. Si vous avez utilisé
serif, chaque OS aurait eu une font diffĂ©rente et donc vous nâauriez pas pu adopter un size-adjust unique. Par ailleurs, Times New Roman a lâavantage dâĂȘtre disponible sur beaucoup dâOS. Si vous cherchez sa contrepartie enserif, alors Arial est certainement le meilleur choix. (Safe web fonts)A noter toutefois que Times New Roman et Arial ne sont pas rĂ©ellement disponibles partout, contrairement Ă ce quâon trouve sur la majoritĂ© des sites qui en parlent. Notamment, elles le seront certainement sur Windows, Mac et Ubuntu. Mais sur mon Manjaro, elles nây sont pas. Si vous ĂȘtes jusquâau-boutiste, il peut ĂȘtre intĂ©ressant dâajouter un deuxiĂšme fallback avec les fonts DejaVu Serif ou DejaVu Sans qui, elles, sont libres de droit et donc largement disponibles dans lâĂ©cosystĂšme Linux.
Vous ne pourrez toutefois jamais ĂȘtre certain que vos font de fallback sont disponibles. Il est donc important de garder la notion de
serifousans-serifdans lafont-family. -
Je vous ai parlé de
size-adjust, mais unascent-overridea fait son apparition. La diffĂ©rence entre les deux est que size-adjust va gĂ©rer lâalignement horizontal tandis que ascent-override sâoccupe de lâalignement vertical.Comment choisir leurs valeursâŻ? La rĂ©ponse la plus simple est avec cet outil qui peut bien vous macher le travail : Automatic font matching. Le seul souci câest quâil part du principe que Arial ou Times New Roman est installĂ© sur votre PC. Si ce nâest pas le cas, il faudra faire la manipulation manuellement en tatonnant jusquâĂ trouver la bonne valeur.
-
Pourquoi dĂ©finir une unicode-range sur le fallbackâŻ? Vous pouvez constater que jâai conservĂ© exactement la mĂȘme unicode-range que pour la font finale. Le but ici est de sâassurer que la font de fallback ne fasse pas trop de zĂšle. Notamment certaines fonts contiennent des emojis noir et blancs. Si vous oubliez de mettre lâunicode-range, vous retrouvez donc avec un emoji en noir et blanc plutĂŽt que lâemoji habituellement affichĂ© par votre navigateur. En renseignant la bonne unicode-range, vous vous assurez que les emojis ne soient pas considĂ©rĂ©s par cette
@font-face. Pour en savoir, cet excellent article rĂ©sume bien lâenfer des emojis (EN) đ -
Enfin, que se passe-t-il si ma font a plusieurs graissesâŻ? En effet, quand on parle de size-adjust on parle dâalignement horizontal. Et la graisse impacte lâespacement horizontal. Vous allez donc avoir besoin dâun size-adjust diffĂ©rent. LâidĂ©e est alors dâajouter une
@font-facedifférente spécialement conçue pour cette graisse en spécifiantfont-weight: 700 :@font-face { font-family: 'Ovo-fallback'; font-weight: 700; /* Adapter la valeur du size-adjust à la font */ size-adjust: 104.1%; ascent-override: 72%; /* Choisir la bonne graisse sur la font de fallback */ src: local('Times New Roman Bold'); unicode-range: U+20-5F, U+61-7A, U+7C, U+A0, U+A7, U+A9, U+AB, U+B2-B3, U+BB, U+C0, U+C2, U+C6-CB, U+CE-CF, U+D4, U+D9, U+DB-DC, U+E0, U+E2, U+E6-EB, U+EE-EF, U+F4, U+F9, U+FB-FC, U+FF, U+152-153, U+178, U+2B3, U+2E2, U+1D48-1D49, U+2010-2011, U+2013-2014, U+2019, U+201C-201D, U+2020-2021, U+2026, U+202F-2030, U+20AC, U+2212; }
Que faire quand size-adjust nâest pas disponibleâŻ?
Je disais un peu plus haut que seulement 73% des navigateurs supportent size-adjust aujourdâhui. Que faire pour les 27% restantsâŻ?
Tout dâabord vous pouvez considĂ©rez que câest du progressive enhancement : alors vous pouvez directement passer Ă la partie suivante sur les Variable Fonts
Sinon, il vous faudra passer par du JavaScript. En effet, ce que nous avons vu, câest que size-adjust et ascent-override permettent de gĂ©rer les espacements horizontaux et verticaux de la font. Mais quand on y pense, câest aussi ce que font letter-spacing et line-height en CSS.
La seule diffĂ©rence est que dans le premier cas vous pouvez le dĂ©finir au niveau dâune font unique, et dans lâautre vous ĂȘtes obligĂ© de dĂ©finir le mĂȘme pour toutes les fonts (fallback et finale).
Lâastuce est alors dâutiliser des classes CSS qui vous permettent de savoir quelle font est en cours dâutilisation :
body {
font-family: 'Times New Roman', serif;
letter-spacing: 0.05em;
line-height: 1.45;
}
.font-loaded body {
font-family: Ovo, serif,
letter-spacing: 0;
line-height: 1.5;
}
Câest une reprĂ©sentation trĂšs simplifiĂ©e de la rĂ©alitĂ©. Vous aurez sĂ»rement besoin de lâadapter pour chaque selecteur CSS qui Ă lâhabitude de manipuler ces propriĂ©tĂ©s (ex : h1, h2, h3, h4, strong, etc.).
Pour obtenir cette nouvelle classe font-loaded, nous devons passer au JavaScript en utilisant FontFaceObserver :
/* Utiliser le mĂȘme nom que celui utilisĂ© dans la propriĂ©tĂ© `font-family` */
const ovoFont = new FontFaceObserver('Ovo');
ovoFont.load().then(() => {
document.documentElement.classList.add('font-loaded');
});
Ainsi, dÚs que la font Ovo a fini de se charger la classe font-loaded est ajoutée.
Ce JavaScript doit ĂȘtre ajoutĂ© de maniĂšre synchrone Ă lâaide dâune balise <script> inline dans le <head> de votre site si vous voulez Ă©viter au maximum un Flash Of Unstyled Text. MĂȘme si la librairie en elle mĂȘme est lĂ©gĂšre (1.3KB gzip), ça reprĂ©sente une lĂ©gĂšre perte de performance et un sacrĂ© effort de maintenabilitĂ© en plus pour penser Ă maintenir tous les letter-spacing & line-height, avec et sans fallback dans votre CSS.
Par ailleurs, il est impossible dâutiliser FontFaceObserver uniquement pour les navigateurs qui ne supportent pas size-adjust. Si vous souhaitez gĂ©rer les 27% de navigateurs qui ne gĂšrent pas size-adjust, vous devrez donc tout le temps passer par FontFaceObserver et subir la lĂ©gĂšre perte de performance et de maintenabilitĂ© que cela reprĂ©sente. La question quâil vous reste Ă rĂ©soudre est donc de savoir si cela vaut le coup ou non.
2. Utiliser plusieurs graisses de fonts grĂące aux Variable Fonts
Nous avons donc vu jusquâĂ maintenant comment charger une unique font custom. La consĂ©quence de ce choix est que si nous avons du gras dans la page, alors le navigateur utilisera de la Font Synthesis : il simulera une graisse en la devinant Ă partir de la font normale.
Parfois câest suffisant, mais parfois⊠câest moche.
Câest lĂ que les variable fonts peuvent ĂȘtre un bon moyen de prĂ©server la simplicitĂ© de chargement et la lĂ©gertĂ© de vos fichiers tout en mettant Ă disposition plusieurs variantes de graisse. De maniĂšre simplifiĂ©e, ça fonctionne en enregistrant dans le fichier les glyphes fins ET les glyphes gras, puis en faisant une interpolation entre les deux pour obtenir la graisse choisie.
Vous en trouverez notamment un bon nombre sur Google Fonts si vous cochez la case âShow only variable fontsâ. Il y a mĂȘme des trucs rigolos avec des fonts colorĂ©es avec des effets 3D.
Si nous revenons à notre code, quelle différence par rapport à la font unique�
Dans le cas de mon blog, jâai choisi la font Assistant. Celle-ci a des graisses allant de 200 Ă 800. La seule diffĂ©rence se trouve au niveau de lâappel Ă @font-face avec lâajout de la propriĂ©tĂ© font-weight :
@font-face {
font-family: 'Assistant';
/* J'indique au navigateur que la font est capable
de gérer des graisses allant de 200 à 800 */
font-weight: 200 800;
font-display: fallback;
src: url(/fonts/Assistant.woff2) format('woff2');
unicode-range: U+20-5F, U+61-7A, U+7C, U+A0, U+A7, U+A9, U+AB, U+B2-B3, U+BB, U+C0, U+C2, U+C6-CB,
U+CE-CF, U+D4, U+D9, U+DB-DC, U+E0, U+E2, U+E6-EB, U+EE-EF, U+F4, U+F9, U+FB-FC, U+FF,
U+152-153, U+178, U+2B3, U+2E2, U+1D48-1D49, U+2010-2011, U+2013-2014, U+2019, U+201C-201D,
U+2020-2021, U+2026, U+202F-2030, U+20AC, U+2212;
}
đ€ A noter que vous verrez dâautres tutos & documentations la possibilitĂ© de changer le format pour indiquer au navigateur que câest une Font Variable.
@font-face { src: url(/fonts/Assistant.woff2) format('woff2') tech('variations'), url(/fonts/Assistant.woff2) format('woff2-variations'); }Malheureusement chez moi ces syntaxes dĂ©sactivent complĂštement les fonts. Pourtant, en restant sur la version simplifiĂ©e tout rentre dans lâordre. Je nâai pas rĂ©ussi Ă trouver dâinformations Ă ce sujet. Etant donnĂ© le support trĂšs large des variable fonts je pars donc du principe que, au pire, ça tĂ©lĂ©chargera la font dans tous les cas et fallbackera si finalement la font ne fonctionne pas sur le navigateur.
Cette notion de font-weight est la seule diffĂ©rence comparĂ©e au chargement dâune font unique. Toutes les autres problĂ©matiques restent identiques. Pensez donc bien Ă Â :
- Optimiser le fichier de font avec
pyftsubset - Utiliser les bonnes rĂšgles de font-display
- GĂ©rer les fallbacks et bien faire attention Ă lâajustement des fallbacks en fonction des diffĂ©rentes graisses
Pour un exemple complet, vous pouvez vous référer à la feuille de style de mon blog.
3. Utiliser plusieurs fonts
Dernier cas de figure : votre site est complexe, repose sur plusieurs fonts ou a minima une font qui a plusieurs graisses sans Font Variable disponible. Comment combiner tout ce quâon a vu jusquâĂ maintenant pour proposer la meilleure solution Ă lâutilisateurâŻ?
Dans les exemples ci-dessous, jâutiliserai Montserrat pour les titres et Cabin pour les paragraphes. En rĂ©alitĂ© celles-ci existent sous form de Font Variables, mais pour mieux illustrer la situation, je considĂ©rerai que non.
3.1. Définir une @font-face par typo
Si on exclut les @font-face de fallback, nous avions eu besoin dâune unique @font-face jusquâĂ maintenant. Si nous avons plusieurs fonts, il va donc falloir duppliquer ces dĂ©clarations pour chacunes dâelles :
@font-face {
font-family: 'Montserrat';
font-weight: 400;
src: url('/fonts/Montserrat.woff2') format('woff2');
}
@font-face {
font-family: 'Montserrat';
font-weight: 700;
src: url('/fonts/Montserrat-Bold.woff2') format('woff2');
}
@font-face {
font-family: 'Cabin';
font-weight: 400;
src: url('/fonts/Cabin.woff2') format('woff2');
}
@font-face {
font-family: 'Cabin';
font-weight: 700;
src: url('/fonts/Cabin-Bold.woff2') format('woff2');
}
Mais cela apporte son lot de complexités :
- Plus de fichiers, donc plus long Ă tĂ©lĂ©charger : il est dâautant plus important de bien optimiser et prioriser vos ressources afin que votre site ait fini de sâafficher au plus vite.
- Chaque font arrive Ă son propre rythme : Admettons que vous receviez la font Cabin, puis, 500ms plus tard, Montserrat arrive pour les titres. A chaque fin de chargement le navigateur va changer le contenu et lâadapter Ă la nouvelle font. Au delĂ de lâeffet sapin de NoĂ«l, le navigateur va ĂȘtre obligĂ© de recalculer lâensemble des positions du site (câest lâĂ©tape de Layout) Ă chaque font chargĂ©e. Cette Ă©tape peut ĂȘtre trĂšs couteuse si vous avez un site complexe (ex : > 1500 Ă©lĂ©ments de DOM) ou qui utilise des systĂšmes de layout particuliĂšrement complexes (ex : beaucoup de flexbox imbriquĂ©es, etc.).
Pour la lenteur de chargement, il sâagit essentiellement de bien optimiser les ressources pour limiter les impacts :
- les fonts sont hĂ©bergĂ©es sur le mĂȘme domaine que votre site
- chaque font a Ă©tĂ© optimisĂ©e grĂące Ă
pyftsubset - chaque
@font-facea le fallback qui va bien en utilisantsize-adjust
Cependant, pour les problĂšmes de rythme, câest plus compliquĂ©. En effet, il nâexiste pas de moyen pour indiquer Ă votre navigateur de ne pas afficher une font tant que lâautre nâest pas chargĂ©e. La solution serait donc dâorchestrer vos chargements de cette façon :
body {
font-family: Cabin-critical, Cabin-fallback, sans-serif;
}
h1,
h2,
h3,
h4,
h5,
blockquote {
font-family: Cabin-critical, Montserrat-fallback, sans-serif;
}
.fonts-loaded body {
font-family: Cabin, Cabin-fallback, sans-serif;
}
.fonts-loaded h1,
.fonts-loaded h2,
.fonts-loaded h3,
.fonts-loaded h4,
.fonts-loaded h5,
.fonts-loaded blockquote {
font-family: Montserrat, sans-serif;
}
-
Afficher une font de fallback en utilisant une de celles dĂ©jĂ installĂ©es sur lâordinateur de votre utilisateurice (ici
sans-serif). -
Afficher ensuite la font la plus impactante en lâoptimisant agressivement.
La font la plus impactante sera généralement celle pour les paragraphes (ici Cabin). Mais si votre site fonctionne essentiellement avec des splashscreens faits uniquement des titres, alors privilégiez celle de vos titres (ici Montserrat).
Vous pouvez lâoptimiser agressivement en rĂ©duisant encore plus le nombre de glyphes Ă disposition. Peut-ĂȘtre pouvez vous vous contenter dâun espace, de 0-9, a-z et A-ZâŻ? Si oui, ce serait les charactĂšres unicodes suivants :
U+20,U+30-39,U+41-51,U+61-7A. Câest plus facile cela dit en anglais quâen français oĂč ça risque de faire lĂ©gĂšrement bizarre pour les accents.pyftsubset \ ./static/fonts/Cabin-Regular.ttf \ --unicodes="U+20,U+30-39,U+41-51,U+61-7A" \ --layout-features='*' \ --flavor=woff2 \ --output-file=./static/fonts/Cabin-Critical.woff2LâintĂ©rĂȘt de cette Ă©tape est que le site respecte les tons typographiques de votre charte trĂšs rapidement, mĂȘme si toutes les fonts nâont pas rĂ©ussi Ă charger.
Par ailleurs dans le cas oĂč vous nâavez quâun seul type de fonts (ex: uniquement Montserrat), mais plusieurs graisses Ă charger, cela vous permet de vous reposer sur la Font Synthesis qui sera vraisemblablement assez proche des graisses finales que vous comptez charger.
Etant donnĂ© que câest la seule font critique au premier affichage, câest sur ce fichier lĂ que vous pouvez ajouter un
<link rel="preload">dans lâentĂȘte de votre site.<head> <link rel="preload" as="font" type="font/woff2" href="/fonts/Cabin-Critical.woff2" crossorigin /> </head> -
Charger toutes les autres fonts et attendre que la totalitĂ© soit tĂ©lĂ©chargĂ©e avant dâajouter la classe
fonts-loadedĂ votre document.Pour faire cela, vous pouvez utiliser la mĂȘme technique que pour les navigateurs qui ne supportent pas
size-adjust : en passant par FontFaceObserverconst cabinFont = new FontFaceObserver('Cabin'); const cabinBoldFont = new FontFaceObserver('Cabin', { { weight: 700 } }); const montserratFont = new FontFaceObserver('Montserrat'); const montserratBoldFont = new FontFaceObserver('Montserrat', { { weight: 700 } }); Promise.all([ cabinFont.load(), cabinBoldFont.load(), montserratFont.load(), montserratBoldFont.load(), ]).then(() => { document.documentElement.classList.add('font-loaded'); });Ainsi, grùce au
Promise.all, on attend que toutes les fonts soient tĂ©lĂ©chargĂ©es avant de les afficher. Le temps que lâon perd Ă attendre lâarrivĂ©e des fonts, on va le gagner en performance ressentie et en temps de calcul pour le navigateur.Attention toutefois Ă bien penser Ă rendre ce script inline et synchrone dans le
<head>de votre page. Ainsi, si les fonts sont déjà en cache, le navigateur sera en mesure de les afficher directement.
Récapitulatif
Nous voilĂ arrivĂ© au bout. FĂ©licitationsâŻ! đ
Si on rĂ©capitule un peu tout ce quâon vient de voir, voici quelques Ă©lĂ©ments que je veux que vous gardiez en tĂȘte :
- commencez par faire le bilan sur vos fonts : lesquelles sont utiles, lesquelles peuvent ĂȘtre Ă©vitĂ©esâŻ?
- est-ce quâil est possible dâutiliser des fonts variablesâŻ?
- Faites en sorte que vos fonts soient les moins bloquantes possible :
- les hĂ©berger sur le mĂȘme nom de domaine que votre site
- veiller Ă ce quâelles soient en cache pour ne pas avoir Ă les retĂ©lĂ©charger Ă la prochaine page
- ajouter des
preloadsur les fonts critiques - optimiser les fonts pour nâavoir que les caractĂšres nĂ©cessaires (
pyftsubset) - utiliser
font-display: fallbackouswappour éviter les pages blanches sur connexions lentes
- Travaillez sur les fonts de fallback pour limiter les effets sapin de Noël :
- en utilisant
size-adjustsur les fonts de fallback - en utilisant FontFaceObserver pour grouper les mises Ă jour en une seule
- en utilisant
PfiouâŻ! Ca en fait des choses. Vous en voyez dâautresâŻ? En tout cas, avec ça vous devriez voir un joli boost de performance sur votre site si ce nâĂ©tait pas dĂ©jĂ en place. NâhĂ©sitez pas Ă me partager vos avancĂ©es Mastodon ou Twitter.
A la semaine prochaine pour la suiteâŻ! Je me concentrerai cette fois sur les icones. đ
Si vous voulez suivre mes publications, il paraĂźt que j'ai un feed RSS, Mastodon et un Twitter.
Si vous pensez à d'autres méthodes que vous voudriez que je mette en place (pigeon voyageur, avion en papier, etc.), n'hésitez pas à me les proposer :)