Ein Workflow für Webfonts ist einfach, oder? Wähle ein paar nett aussehende, webtaugliche Schriftarten, besorge dir den HTML- oder CSS-Code-Schnipsel, füge ihn ins Projekt ein und prüfe, ob sie richtig angezeigt werden. Leute machen das mit Google Fonts milliardenfach am Tag und fügen dessen <link>-Tag in den <head> ein.
Schauen wir uns an, was Lighthouse zu diesem Workflow zu sagen hat.

<head> wurden von Lighthouse als render-blockierende Ressourcen markiert, und sie verursachen eine Verzögerung von einer Sekunde beim Rendern? Nicht gut.Wir haben alles nach Lehrbuch, Dokumentation und HTML-Standards gemacht, also warum sagt uns Lighthouse, dass alles falsch ist?
Lassen Sie uns darüber sprechen, wie man Schriftarten-Stylesheets als render-blockierende Ressource eliminiert, und einen optimalen Aufbau durchgehen, der nicht nur Lighthouse zufriedenstellt, sondern auch den gefürchteten Flash of unstyled text (FOUT) überwindet, der normalerweise beim Laden von Schriftarten auftritt. Wir machen das alles mit reinem HTML, CSS und JavaScript, damit es auf jeden Tech-Stack angewendet werden kann. Als Bonus betrachten wir auch eine Gatsby-Implementierung sowie ein Plugin, das ich als einfache Drop-in-Lösung entwickelt habe.
Was wir unter „render-blockierenden“ Schriftarten verstehen
Wenn der Browser eine Website lädt, erstellt er einen Render-Baum aus dem DOM, d. h. einem Objektmodell für HTML, und CSSOM, d. h. einer Karte aller CSS-Selektoren. Ein Render-Baum ist Teil eines kritischen Renderpfads, der die Schritte darstellt, die der Browser durchläuft, um eine Seite zu rendern. Damit der Browser eine Seite rendern kann, muss er das HTML-Dokument und jede CSS-Datei laden und parsen, die in diesem HTML verlinkt ist.
Hier ist ein ziemlich typisches Schriftarten-Stylesheet, direkt von Google Fonts bezogen
@font-face {
font-family: 'Merriweather';
src: local('Merriweather'), url(https://fonts.gstatic.com/...) format('woff2');
}
Sie denken vielleicht, dass Schriftarten-Stylesheets wegen ihrer geringen Dateigröße unbedeutend sind, da sie normalerweise höchstens ein paar @font-face-Definitionen enthalten. Sie sollten keinen spürbaren Einfluss auf das Rendern haben, oder?
Nehmen wir an, wir laden eine CSS-Schriftartendatei von einem externen CDN. Wenn unsere Website lädt, muss der Browser warten, bis diese Datei vom CDN geladen und in den Render-Baum aufgenommen wird. Nicht nur das, er muss auch auf die Schriftartendatei warten, die als URL-Wert in der CSS @font-face-Definition referenziert wird, um angefordert und geladen zu werden.
Fazit: Die Schriftartendatei wird Teil des kritischen Renderpfads und erhöht die Verzögerung beim Rendern der Seite.

(Quelle: web.dev unter Creative Commons Attribution 4.0 Lizenz)
Was ist der wichtigste Teil einer Website für den durchschnittlichen Nutzer? Der Inhalt, natürlich. Deshalb muss der Inhalt dem Nutzer so schnell wie möglich im Ladeverfahren einer Website angezeigt werden. Um dies zu erreichen, muss der kritische Renderpfad auf kritische Ressourcen (z. B. HTML und kritisches CSS) reduziert werden, wobei alles andere nach dem Rendern der Seite geladen wird, einschließlich der Schriftarten.
Wenn ein Nutzer eine nicht optimierte Website über eine langsame, unzuverlässige Verbindung besucht, wird er verärgert sein, auf einem leeren Bildschirm zu sitzen und auf das Laden von Schriftartendateien und anderen kritischen Ressourcen zu warten. Das Ergebnis? Sofern dieser Nutzer nicht übermäßig geduldig ist, wird er wahrscheinlich einfach aufgeben und das Fenster schließen, in der Annahme, dass die Seite gar nicht lädt.
Wenn jedoch nicht-kritische Ressourcen aufgeschoben werden und der Inhalt so schnell wie möglich angezeigt wird, kann der Nutzer die Website durchsuchen und fehlende präsentationsspezifische Stile (wie Schriftarten) ignorieren – vorausgesetzt, sie behindern den Inhalt nicht.

Der optimale Weg zum Laden von Schriftarten
Es hat keinen Sinn, das Rad neu zu erfinden. Harry Roberts hat bereits gute Arbeit geleistet, indem er einen optimalen Weg zum Laden von Webfonts beschreibt. Er geht sehr detailliert mit gründlicher Recherche und Daten von Google Fonts vor und fasst alles in einem Vier-Schritte-Prozess zusammen.
- Preconnect zum Ursprung der Schriftartendatei.
- Preload des Schriftarten-Stylesheets asynchron mit geringer Priorität.
- Asynchrones Laden des Schriftarten-Stylesheets und der Schriftartendatei nach dem Rendern des Inhalts mit JavaScript.
- Bereitstellen einer Fallback-Schriftart für Benutzer mit deaktiviertem JavaScript.
Lassen Sie uns unsere Schriftart nach Harrys Ansatz implementieren.
<!-- https://fonts.gstatic.com is the font file origin -->
<!-- It may not have the same origin as the CSS file (https://fonts.googleapis.com) -->
<link rel="preconnect"
href="https://fonts.gstatic.com"
crossorigin />
<!-- We use the full link to the CSS file in the rest of the tags -->
<link rel="preload"
as="style"
href="https://fonts.googleapis.com/css2?family=Merriweather&display=swap" />
<link rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Merriweather&display=swap"
media="print" onload="this.media='all'" />
<noscript>
<link rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Merriweather&display=swap" />
</noscript>
Beachten Sie das media="print" im Link zum Schriftarten-Stylesheet. Browser geben Druck-Stylesheets automatisch eine niedrige Priorität und schließen sie vom kritischen Renderpfad aus. Nachdem das Druck-Stylesheet geladen wurde, wird ein onload-Ereignis ausgelöst, das Medium wird auf einen Standardwert all geändert und die Schriftart wird auf alle Medientypen (Bildschirm, Druck und Sprache) angewendet.

Es ist wichtig zu beachten, dass das Selbst-Hosting von Schriftarten auch helfen kann, render-blockierende Probleme zu beheben, aber das ist nicht immer möglich. Die Verwendung eines CDN zum Beispiel kann unvermeidlich sein. In einigen Fällen ist es vorteilhaft, die Hauptlast beim Ausliefern statischer Ressourcen einem CDN zu überlassen.
Obwohl wir nun das Schriftarten-Stylesheet und die Schriftartendateien auf dem optimalen, nicht-render-blockierenden Weg laden, haben wir ein kleines UX-Problem eingeführt...
Flash of unstyled text (FOUT)
Das nennen wir FOUT.

Warum passiert das? Um eine render-blockierende Ressource zu eliminieren, müssen wir sie laden, nachdem der Seiteninhalt gerendert (d. h. auf dem Bildschirm angezeigt) wurde. Im Fall eines niedrig priorisierten Schriftarten-Stylesheets, das asynchron nach kritischen Ressourcen geladen wird, kann der Nutzer den Moment sehen, in dem sich die Schriftart von der Fallback-Schriftart zur heruntergeladenen Schriftart ändert. Nicht nur das, das Layout der Seite kann sich verschieben, was dazu führt, dass einige Elemente kaputt aussehen, bis die Webfont geladen ist.
Der beste Weg, mit FOUT umzugehen, ist, den Übergang zwischen der Fallback-Schriftart und der Webfont reibungslos zu gestalten. Um das zu erreichen, müssen wir
- Eine geeignete Fallback-Systemschriftart auswählen, die der asynchron geladenen Schriftart so genau wie möglich entspricht.
- Die Schriftartenstile anpassen (
font-size,line-height,letter-spacingusw.) der Fallback-Schriftart, um die Eigenschaften der asynchron geladenen Schriftart wieder so genau wie möglich anzupassen. - Die Stile für die Fallback-Schriftart löschen, sobald die asynchron geladene Schriftartendatei gerendert wurde, und die für die neu geladene Schriftart vorgesehenen Stile anwenden.
Wir können Font Style Matcher verwenden, um optimale Fallback-Systemschriftarten zu finden und diese für jede geplante Webfont zu konfigurieren. Sobald wir Stile sowohl für die Fallback- als auch für die Webfont bereit haben, können wir mit dem nächsten Schritt fortfahren.

Wir können die CSS Font Loading API verwenden, um zu erkennen, wann unsere Webfont geladen ist. Warum das? Typekit's Web Font Loader war einst eine der beliebtesten Methoden dafür, und obwohl es verlockend ist, ihn oder ähnliche Bibliotheken weiterhin zu verwenden, müssen wir Folgendes berücksichtigen:
- Er wurde seit über vier Jahren nicht mehr aktualisiert, was bedeutet, dass, wenn auf der Plugin-Seite etwas fehlschlägt oder neue Funktionen benötigt werden, es wahrscheinlich niemand implementieren und warten wird.
- Wir handhaben das asynchrone Laden bereits effizient mit Harry Roberts' Snippet und wir müssen uns nicht auf JavaScript verlassen, um die Schriftart zu laden.
Wenn Sie mich fragen, ist die Verwendung einer Typekit-ähnlichen Bibliothek einfach zu viel JavaScript für eine so einfache Aufgabe. Ich möchte keine Drittanbieter-Bibliotheken und Abhängigkeiten verwenden, also implementieren wir die Lösung selbst und versuchen, sie so einfach und unkompliziert wie möglich zu gestalten, ohne sie zu überkomplizieren.
Obwohl die CSS Font Loading API als experimentelle Technologie gilt, hat sie eine Browserunterstützung von etwa 95 %. Aber unabhängig davon sollten wir eine Fallback-Lösung bereitstellen, falls die API in Zukunft geändert oder als veraltet eingestuft wird. Das Risiko, eine Schriftart zu verlieren, ist die Mühe nicht wert.
Die CSS Font Loading API kann zum dynamischen und asynchronen Laden von Schriftarten verwendet werden. Wir haben bereits entschieden, uns nicht auf JavaScript für etwas so Einfaches wie das Laden von Schriftarten zu verlassen, und wir haben es auf optimale Weise mit reinem HTML mit Preload und Preconnect gelöst. Wir werden eine einzelne Funktion aus der API verwenden, die uns hilft zu prüfen, ob die Schriftart geladen und verfügbar ist.
document.fonts.check("12px 'Merriweather'");
Die Funktion check() gibt true oder false zurück, je nachdem, ob die in den Funktionsargumenten angegebene Schriftart verfügbar ist oder nicht. Der Wert des Parameters für die Schriftgröße ist für unseren Anwendungsfall nicht wichtig und kann auf jeden Wert gesetzt werden. Dennoch müssen wir sicherstellen, dass
- Wir mindestens ein HTML-Element auf einer Seite haben, das mindestens ein Zeichen mit einer deklarierten Webfont enthält. In den Beispielen verwenden wir
, aber jedes Zeichen kann verwendet werden, solange es (ohnedisplay: none;) sowohl für sehende als auch für nicht-sehende Benutzer verborgen ist. Die API verfolgt DOM-Elemente, auf die Schriftartenstile angewendet werden. Wenn keine passenden Elemente auf einer Seite vorhanden sind, kann die API nicht feststellen, ob die Schriftart geladen wurde oder nicht. - Die in den Argumenten der Funktion
check()angegebene Schriftart ist genau das, wie die Schriftart im CSS genannt wird.
Ich habe den Listener für das Laden von Schriftarten mit der CSS Font Loading API in der folgenden Demo implementiert. Zu Demonstrationszwecken werden das Laden von Schriftarten und der Listener dafür durch Klicken auf die Schaltfläche ausgelöst, um einen Seitenlade-Vorgang zu simulieren, damit Sie die Änderung sehen können. In regulären Projekten sollte dies bald nach dem Laden und Rendern der Website geschehen.
Ist das nicht großartig? Wir haben weniger als 30 Zeilen JavaScript benötigt, um einen einfachen Listener für das Laden von Schriftarten zu implementieren, dank einer gut unterstützten Funktion aus der CSS Font Loading API. Wir haben auch zwei mögliche Randfälle im Prozess behandelt:
- Etwas geht mit der API schief oder es tritt ein Fehler auf, der das Laden der Webfont verhindert.
- Der Benutzer besucht die Website mit deaktiviertem JavaScript.
Jetzt, da wir eine Möglichkeit haben zu erkennen, wann die Schriftartendatei fertig geladen ist, müssen wir unserer Fallback-Schriftart Stile hinzufügen, um die Webfont anzupassen, und sehen, wie FOUT effektiver gehandhabt wird.
Der Übergang zwischen der Fallback-Schriftart und der Webfont sieht reibungslos aus und wir haben es geschafft, einen wesentlich weniger auffälligen FOUT zu erzielen! Auf einer komplexen Website würde diese Änderung zu weniger Layout-Shifts führen, und Elemente, die von der Inhaltsgröße abhängen, würden nicht kaputt oder deplatziert aussehen.
Was unter der Haube passiert
Werfen wir einen genaueren Blick auf den Code aus dem vorherigen Beispiel, beginnend mit dem HTML. Wir haben den Schnipsel im <head>-Element, der es uns ermöglicht, die Schriftart asynchron mit Preload, Preconnect und Fallback zu laden.
<body class="no-js">
<!-- ... Website content ... -->
<div aria-visibility="hidden" class="hidden" style="font-family: '[web-font-name]'">
/* There is a non-breaking space here */
</div>
<script>
document.getElementsByTagName("body")[0].classList.remove("no-js");
</script>
</body>
Beachten Sie, dass wir eine fest codierte Klasse .no-js im <body>-Element haben, die entfernt wird, sobald das HTML-Dokument vollständig geladen ist. Dies wendet Webfont-Stile für Benutzer mit deaktiviertem JavaScript an.
Zweitens, erinnern Sie sich, wie die CSS Font Loading API mindestens ein HTML-Element mit einem einzelnen Zeichen benötigt, um die Schriftart zu verfolgen und ihre Stile anzuwenden? Wir haben ein <div> mit einem -Zeichen hinzugefügt, das wir auf zugängliche Weise sowohl für sehende als auch für nicht-sehende Benutzer verstecken, da wir display: none; nicht verwenden können. Dieses Element hat einen inline font-family: 'Merriweather'-Stil. Dies ermöglicht es uns, reibungslos zwischen den Fallback-Stilen und den geladenen Schriftartenstilen zu wechseln und sicherzustellen, dass alle Schriftartendateien ordnungsgemäß verfolgt werden, unabhängig davon, ob sie auf der Seite verwendet werden oder nicht.
Beachten Sie, dass das -Zeichen nicht im Code-Schnipsel angezeigt wird, aber es ist da!
Der CSS ist der einfachste Teil. Wir können die CSS-Klassen nutzen, die im HTML fest codiert sind oder bedingt mit JavaScript angewendet werden, um verschiedene Zustände des Schriftartenladens zu handhaben.
body:not(.wf-merriweather--loaded):not(.no-js) {
font-family: [fallback-system-font];
/* Fallback font styles */
}
.wf-merriweather--loaded,
.no-js {
font-family: "[web-font-name]";
/* Webfont styles */
}
/* Accessible hiding */
.hidden {
position: absolute;
overflow: hidden;
clip: rect(0 0 0 0);
height: 1px;
width: 1px;
margin: -1px;
padding: 0;
border: 0;
}
JavaScript ist die Magie. Wie bereits beschrieben, prüfen wir, ob die Schriftart geladen wurde, indem wir die check()-Funktion der CSS Font Loading API verwenden. Auch hier kann der Parameter für die Schriftgröße jeder Wert (in Pixeln) sein; der Wert der Schriftfamilie muss dem Namen der Schriftart entsprechen, die wir laden.
var interval = null;
function fontLoadListener() {
var hasLoaded = false;
try {
hasLoaded = document.fonts.check('12px "[web-font-name]"')
} catch(error) {
console.info("CSS font loading API error", error);
fontLoadedSuccess();
return;
}
if(hasLoaded) {
fontLoadedSuccess();
}
}
function fontLoadedSuccess() {
if(interval) {
clearInterval(interval);
}
/* Apply class names */
}
interval = setInterval(fontLoadListener, 500);
Was hier passiert, ist, dass wir unseren Listener mit fontLoadListener() einrichten, der in regelmäßigen Abständen läuft. Diese Funktion sollte so einfach wie möglich sein, damit sie effizient innerhalb des Intervalls läuft. Wir verwenden den try-catch-Block, um Fehler zu behandeln und Probleme abzufangen, sodass Webfont-Stile auch im Falle eines JavaScript-Fehlers angewendet werden, damit der Benutzer keine UI-Probleme erfährt.
Als Nächstes berücksichtigen wir den Fall, dass die Schriftart erfolgreich geladen wird, mit fontLoadedSuccess(). Wir müssen sicherstellen, dass wir zuerst das Intervall löschen, damit die Überprüfung nicht unnötigerweise danach läuft. Hier können wir Klassennamen hinzufügen, die wir benötigen, um die Webfont-Stile anzuwenden.
Und schließlich starten wir das Intervall. In diesem Beispiel haben wir es auf 500 ms eingestellt, sodass die Funktion zweimal pro Sekunde ausgeführt wird.
Hier ist eine Gatsby-Implementierung
Gatsby macht im Vergleich zur reinen Webentwicklung (und sogar zum regulären Create-React-App-Tech-Stack) ein paar Dinge anders, was die Implementierung des bisher Behandelten etwas knifflig macht.
Um dies zu vereinfachen, entwickeln wir ein lokales Gatsby-Plugin, sodass sich der gesamte Code, der für unseren Schriftartenlader relevant ist, im Beispiel unten unter plugins/gatsby-font-loader befindet.
Unser Schriftartenlader-Code und die Konfiguration werden auf die drei Haupt-Gatsby-Dateien aufgeteilt.
- Plugin-Konfiguration (
gatsby-config.js): Wir werden das lokale Plugin in unser Projekt aufnehmen, alle lokalen und externen Schriftarten und ihre Eigenschaften auflisten (einschließlich des Schriftartennamens und der CSS-Datei-URL) und alle Preconnect-URLs einfügen. - Server-seitiger Code (
gatsby-ssr.js): Wir werden die Konfiguration verwenden, um Preload- und Preconnect-Tags im HTML-<head>mithilfe der FunktionsetHeadComponentsaus der Gatsby-API zu generieren und einzufügen. Dann generieren wir die HTML-Snippets, die die Schriftart verstecken, und fügen sie übersetPostBodyComponentsin HTML ein. - Client-seitiger Code (
gatsby-browser.js): Da dieser Code ausgeführt wird, nachdem die Seite geladen wurde und nachdem React gestartet ist, ist er bereits asynchron. Das bedeutet, wir können die Schriftarten-Stylesheet-Links mit react-helmet einfügen. Wir starten auch einen Schriftarten-Lade-Listener, um FOUT zu behandeln.
Sie können die Gatsby-Implementierung im folgenden CodeSandbox-Beispiel ansehen.
Ich weiß, einige dieser Dinge sind komplex. Wenn Sie nur eine einfache Drop-in-Lösung für performantes, asynchrones Schriftartenladen und FOUT-Bekämpfung wünschen, habe ich ein gatsby-omni-font-loader-Plugin genau dafür entwickelt. Es verwendet den Code aus diesem Artikel und ich pflege es aktiv. Wenn Sie Vorschläge, Fehlerberichte oder Codebeiträge haben, können Sie diese gerne auf GitHub einreichen.
Fazit
Der Inhalt ist vielleicht die wichtigste Komponente für die Benutzererfahrung auf einer Website. Wir müssen sicherstellen, dass der Inhalt oberste Priorität hat und so schnell wie möglich geladen wird. Das bedeutet, dass während des Ladevorgangs minimale präsentationsspezifische Stile (d. h. inline kritisches CSS) verwendet werden. Deshalb werden Webfonts in den meisten Fällen als nicht-kritisch betrachtet – der Nutzer kann den Inhalt auch ohne sie konsumieren – daher ist es völlig in Ordnung, wenn sie nach dem Rendern der Seite geladen werden.
Das kann jedoch zu FOUT und Layout-Shifts führen, daher ist der Listener für das Laden von Schriftarten erforderlich, um einen reibungslosen Wechsel zwischen der Fallback-Systemschriftart und der Webfont zu ermöglichen.
Ich würde gerne Ihre Gedanken dazu hören! Lassen Sie mich in den Kommentaren wissen, wie Sie das Problem des Webfont-Ladens, render-blockierender Ressourcen und FOUT auf Ihren Projekten angehen.
Referenzen
- Render-blockierende Ressourcen eliminieren (web.dev)
- Optimierung des Ladens und Renderns von Webfonts (web.dev)
- Render Blocking CSS (Google Web Fundamentals)
- Die schnellsten Google Fonts (CSS Wizardry)
- CSS-Grundlagen: Fallback-Schriftstapel für robustere Webtypografie (CSS-Tricks)
- CSS Font Loading API (MDN)
- Font Style Matcher
Danke dafür. Wie immer ergab alles Sinn, bis Sie anfingen, Gatsby zu erwähnen :)
Freut mich, dass Ihnen der Artikel gefallen hat. Ich wollte eine Gatsby-Implementierung als Bonus abdecken, daher kann die Idee und der Code bis zum letzten Abschnitt auf das Framework und den Tech-Stack Ihrer Wahl angewendet werden.
Das ist Zufall, ich habe gestern fast meine ganze Zeit mit genau diesem Thema verbracht, nachdem ich von Pagespeed Insights abgestraft wurde. Dann, nach einem E-Mail-Austausch über die Implementierung dieser Art von Thema mit dem Entwickler meines Joomla-Frameworks, wies er mich auf diesen Artikel hin, der erst gestern veröffentlicht wurde! Es scheint, als ob kluge Köpfe gleich denken :). Aber im Ernst, das Finden dieser Anpassungen zur Verbesserung der Seitenladezeiten bei Google wird bald allen zugute kommen. Insbesondere angesichts der bevorstehenden Änderung des Google-Algorithmus, langsame Websites den Nutzern anzuzeigen (auf die gleiche Weise, wie es bei Nicht-HTTPS-Seiten geschieht, d. h. eine leere Seite mit einer Warnung und einem kleinen Link „Sind Sie sicher?“ unten), die Millionen von Websites betreffen wird. Anpassungen wie diese werden den Unterschied ausmachen.
Vielen Dank, dass Sie sich die Zeit genommen haben, dies zusammenzustellen! Ich hatte den Begriff FOUT noch nie gehört, aber ich habe mich schon eine Weile gefragt, wie ich ihn beheben kann. Ich werde diese Seite auf jeden Fall für mein nächstes Projekt als Lesezeichen speichern.
Vielen Dank. Freut mich zu hören, dass Ihnen der Artikel gefallen hat und Sie planen, FOUT-Handling in Ihrem nächsten Projekt einzusetzen!
Der Font-Loading-„Observer“ ist ziemlich clever, aber ich bin mir nicht sicher, warum Sie ihn überhaupt verwenden, wenn
document.fonts.load(...).then(...)existiert. Das entfernt die HTML-Zeile mit dem und vereinfacht den Code erheblich.Guter Punkt, aber betrachten Sie es so:
Font-Laden – es ist „essenziell“ für die Präsentation von Websites. Wir möchten es so nah wie möglich am nativen Verhalten halten, daher habe ich mich für HTML mit JavaScript-Fallback entschieden. Ich möchte auch nicht, dass es von einer experimentellen API abhängt, die sich jederzeit ändern kann. Ich muss sowieso eine HTML-Fallback-Lösung bereitstellen, falls mit der Spezifikation etwas passiert oder der Browser die API nicht unterstützt.
FOUT-Handling – nützlich, aber nicht essenziell. Wenn sich die Font-API ändert oder nicht unterstützt wird, ist das einzige Problem ein kleiner visueller Glitch. Kein echtes Problem. Also kann ich JavaScript dafür verwenden.
Daher empfehle ich, es so zu machen, bis die Spezifikation endgültig und nicht mehr experimentell ist.
Meine Gedanken: Ich mag es nicht.
Ich mag keine Skeleton-Loader, Schriftarten oder Bilder oder irgendetwas anderes, das herumspringt, nachdem der Inhalt erscheint – das ist ablenkend.
Lösen Sie Ihre Performance-Probleme, anstatt clevere Workarounds zu erfinden. Wählen Sie kleinere Schriftarten. Weniger Schriftarten. Preloaden Sie alle Schriftarten, die oberhalb des Falzes sichtbar sind. Verwenden Sie HTTP/2. Base64-kodieren und inline, wenn es sein muss.
Diese ganze Geschichte von „wahrgenommener Performance“ ist eine Ausrede, um zugrunde liegende technische oder gestalterische Probleme zu vermeiden. Es ist eine verlockende Gelegenheit, Ihre kreative Muskeln spielen zu lassen und „clevere“ Workarounds zu entwickeln.
Aber nichts davon ist notwendig. Gute Webfonts sind für das Web optimiert. Gutes Design verwendet im Allgemeinen nicht mehr als zwei Schriftarten. Gute Implementierungen optimieren durch Komprimierung, Inlining, Preloading, was auch immer nötig ist, um das beabsichtigte Erlebnis zu liefern.
Nur meine Meinung, aber ich sehe so viele dieser Techniken als Ablenkung von den wirklichen Problemen, während sie immer zumindest einige unnötige Komplexität hinzufügen.
Die Lösung von Performance-Problemen auf traditionelle Weise ist vielleicht nicht neu, aufregend oder spaßig – aber ich glaube nicht, dass jemand auf „wahrgenommene Performance“-Workarounds zurückgreifen sollte, bevor alle anderen Optionen ausgeschöpft sind.
Hallo Rasmus, danke für deine Eingabe.
Ich stimme zu, dass man die zugrunde liegenden Probleme beheben und sich mit dem System auseinandersetzen sollte, anstatt Komplexität hinzuzufügen. Deshalb wollte ich meine Implementierung so nah wie möglich an den nativen Funktionalitäten halten (keine Abhängigkeiten, keine Bibliotheken, keine Hacks).
Ich betrachte es sicherlich nicht als „den besten Weg, Schriftarten zu laden und FOUT zu behandeln“, sondern eher als Sprungbrett zu einer besseren Lösung und eine schnelle Lösung, die für die meisten Szenarien funktioniert.
Die Optimierung von Webfonts ist ein komplexes Thema (wie auch die Bildoptimierung oder jede Weboptimierung). Ich habe mir tatsächlich angesehen, wie das Laden von Schriftarten für CSS-Tricks gemacht wurde, und es ist eine Herausforderung: https://www.zachleat.com/web/css-tricks-web-fonts/
Ich denke, Ihre Lösung ist ideal, aber sie hängt stark vom Szenario ab. Manchmal verwendet ein Kunde eine lizenzierte Schriftart, die von einem externen Server geladen wird, und hat keine Kontrolle über die Schriftartendatei selbst. Manchmal passen diese Optimierungsaufgaben nicht zum Budget oder Zeitplan des Kunden. Und die komplexe Lösung erfordert etwas Voraussicht und Entwicklererfahrung, um sie sicher und ohne zukünftige Probleme umzusetzen.
Zuletzt denke ich, dass dies geringfügige Probleme behebt, die Browser haben – sie zeigen den Inhalt nicht an, während die Schriftartendatei geladen wird. Ich finde es unnötig, dass die Anzeige des Inhalts von der Schriftartendatei abhängt, und ich wollte den FOUT beheben, der durch asynchrones Laden entsteht.
Ich denke, der Ansatz sollte vom Szenario, der Komplexität des Projekts, den Entwicklerfähigkeiten und der Erfahrung sowie der verfügbaren Zeit und dem Budget abhängen.
Interessanter Ansatz. Aber die Verwendung von setTimeout/setInterval kann zu Inkonsistenzen und Verzögerungen führen, die den Check auf das Laden der Schriftarten potenziell verlängern können, da wir hier von einer schnell auftretenden visuellen Änderung sprechen, was sehr wirkungsvoll sein kann. https://hackwild.com/article/web-worker-timers/. Außerdem, haben Sie vielleicht die Ergebnisse Ihrer Technik mit nur der Verwendung von font-display:swap verglichen? Danke für den Artikel!
Hallo Mihovil, danke für deinen Kommentar.
Was die Leistung von „setInterval“ betrifft, habe ich einige Nachforschungen zu dem Thema angestellt. Im Allgemeinen sollte man nur eine einfache Funktion innerhalb des Intervalls haben, damit wir keine größeren Leistungshindernisse haben. Wir verwenden eine einfache native API-Prüfung (die nicht von HTTP-Anfragen oder komplexen Operationen abhängt), also sind wir in diesem Punkt gut aufgestellt. Es ist kein Problem, wenn der Timer nicht präzise ist, wir wollen ihn nur gelegentlich ausführen und prüfen, ob die Schriftart geladen ist. Ich hoffe, das macht die Implementierung etwas klarer.
Was „font-display: swap“ betrifft, das ist ein guter Ansatz, aber das Problem ist, dass man den Wechsel zwischen der Fallback-Schriftart und der Hauptschriftart immer noch bemerkt. Die Breiten- und Höhenunterschiede zwischen der Hauptschriftart und der Fallback-Schriftart könnten zu ärgerlichen Layout-Shifts führen oder einige Elemente kaputt aussehen lassen, abhängig vom Layout und der Bildschirmgröße. Mit dem FOUT-Ansatz können wir erkennen, wann die Hauptschriftart fertig geladen ist, und eine CSS-Klasse (Schriftartenstile) umschalten, sodass der Layout-Shift nicht auftritt und das Umschalten nicht bemerkbar ist.
Toller Artikel, Adrian! Wusste nicht, dass eine Schriftartendatei die Seitenrender-Verzögerung erhöhen kann.
Danke. Freut mich, dass es Ihnen gefallen hat!
Ich habe festgestellt, dass das Selbst-Hosting meiner Schriftarten so ziemlich alle Probleme löst, die Webfonts verursachen können. Nützliches Werkzeug zur Hilfe: https://google-webfonts-helper.herokuapp.com/fonts
Danke für diesen sehr zeitnahen Artikel, Adrian! In Ihrem Beispiel sind alle Schriftgrößen in Pixeln angegeben. Auf den von mir erstellten Websites verwende ich Formeln für variable Schriftgrößen, mit calc() oder clamp(). Ich frage mich, ob Sie Vorschläge haben, wie man FOUT handhabt, wenn die Schriftgrößen alle variabel sind?
Beispiel:
font-size: calc(1.3125rem + (75vw - 15rem)/65.375);Nehmen wir an, die Kopfzeile hat ein Menü, und darunter befindet sich ein Heldenbereich. Der Text für die Menüpunkte sowie die Helden werden alle unterschiedliche Schriftgrößen haben, keine festen Pixelwerte. Das macht den Schriftartenwechsel eher schwierig zu implementieren und mit möglichst wenig Layout-Shifts.
Hallo Zach, danke. Das ist eine tolle Frage.
Das Abgleichen von Schriftarten ist knifflig, daher denke ich, dass variable Schriftarten dies noch kniffliger machen. Ich habe das selbst noch nicht ausprobiert, aber ich vermute, dass man den Font-Style-Matcher verwendet und Übereinstimmungen für die minimale und maximale Schriftgröße aus dem von Ihnen bereitgestellten Calc-Snippet findet. Dasselbe sollte mit dem Zeichenabstand, Wortabstand, Zeilenhöhe usw. geschehen – im Grunde alles, was mit Typografie zu tun hat. Am Ende haben Sie eine Reihe von Calc-Funktionen für sowohl die Fallback-Schriftart als auch die Hauptschriftart.
Im Idealfall sollten die Parameter der Fallback-Schriftart linear mit den Parametern der Hauptschriftart übereinstimmen, damit die Änderungen bei der Auflösung konsistent sind und FOUT ordnungsgemäß behandelt wird.
Lassen Sie mich die Ergebnisse wissen, wenn Sie dies ausprobieren.
Der Beispielcode zeigt die Eigenschaft aria-visibility. Aber dieses Tag existiert nicht (zumindest habe ich in der Spezifikation nichts gefunden). Ich glaube, es sollte stattdessen aria-hidden="true" sein.
Vielen Dank für den Artikel, er hat sehr geholfen! Lassen Sie mich meine zwei Cents hinzufügen. )
Warum verwenden Sie nicht document.fonts.ready.then(), das scheinbar die gleiche Browserabdeckung wie check() hat? Kein Bedarf für setInterval()!
Sie können auch .fonts-loader::before { content: “\00a0”; font-family: ‘Merriweather’; } verwenden, um HTML etwas sauberer zu halten. “\00a0” – ist ein
Vielen Dank für den Artikel! Ein Punkt ist mir nicht ganz klar. Wo fügen Sie das Skript mit setInterval ein? Am Ende des Body-Tags, nach dem Skript, das die no-js-Klasse entfernt, oder davor? (Oder im Head-Tag?)
Viele dieser Artikel konzentrieren sich auf Google Fonts. Was ist, wenn eine Website Adobe Fonts verwendet? Gibt es Tricks für diese? Wie kann man ein Werkzeug wie den Font Style Matcher mit Adobe Fonts verwenden? Ich bin neu in diesem Optimierungszeug.
Großartige Ausarbeitung. Ich habe kürzlich benutzerdefinierte Schriftarten auf meinem Blog deaktiviert und… ich kann den Look einfach nicht mehr ertragen. Ich erinnere mich nicht, Helvetica und Arial so gehasst zu haben, als ich jünger war. Aber jetzt sieht es als Schriftart für lange Texte einfach unprofessionell aus. Ich mache mir keine allzu großen Sorgen um FOUT – ich möchte einfach nur, dass irgendwann eine schön aussehende Schriftart geladen wird.
Es scheint, dass die Schriftgröße wichtig ist; sie kann nicht jeder Wert sein.
Besuchen Sie den folgenden Pen in der Debug-Ansicht, der von Ihrem Pen abgezweigt wurde, um das schnelle Laden der Schriftart zu ermöglichen, und sehen Sie sich die Konsolenausgabe an
https://cdpn.io/pen/debug/NWLavry
Die Ausgabe wird sein
Andere Größen werden nicht geladen, bis die
12pxFontFace geladen ist.Wenn Sie dies auf "Slow 3G" in der Registerkarte "Netzwerk" der Entwicklertools einstellen, wird es noch deutlicher, dass die 12px-Schriftart möglicherweise geladen wird, aber die 24px-Schriftart nicht, und wir können manchmal FOUT sehen.
Basierend darauf scheint der wirklich richtige Weg, um sicherzustellen, dass eine Schriftart geladen wird, darin zu bestehen, auf die übereinstimmenden Schriftgrößen- *und* Schriftartnamenkombinationen zu warten, die unsere App verwendet (dies kann mühsam zu verfolgen sein).
Ich vermute, dass eine FontFace für eine bestimmte Kombination aus Schriftgröße und Name als geladen betrachtet wird, sobald die Bitmap für diese spezifische Größe und diesen Namen berechnet wurde. Der Prozess, mit dem der Browser diese Berechnungen durchführt, wird aufgrund dessen, was ich sehe, als asynchron impliziert und würde erklären, warum die Font Loading API die Angabe der Schriftgröße erfordert (ich würde nicht daran zweifeln, dass die Berechnungen als Optimierung auf separaten Threads erfolgen).