Verhindern des Performance-Einbruchs durch benutzerdefinierte Schriftarten

Avatar of Chris Coyier
Chris Coyier am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

Das Problem ist: 1) Benutzerdefinierte Schriftarten sind großartig und wir wollen sie verwenden. 2) Benutzerdefinierte Schriftarten verlangsamen unsere Seiten, da sie zusätzliche, große Ressourcen darstellen. Die Bewältigung dessen ist in letzter Zeit ein Thema, daher dachte ich, ich fasse einige der Ideen zusammen und füge meine eigenen Gedanken hinzu.

Nur für große Bildschirme laden

Die erste Idee, die ich sah, waren Dave Ruperts Tests zum Laden von @font-face nur auf großen Bildschirmen. Es stellt sich heraus, dass, wenn Sie @font-face verwenden, aber die Schriftartfamilie nie anwenden, die Schriftart nicht heruntergeladen wird. Ziemlich clever, Browser. Daves Demo.

@font-face {
  font-family: 'Dr Sugiyama';
  font-style: normal;
  font-weight: 400;
  src: local("Dr Sugiyama Regular"), local("DrSugiyama-Regular"), url(http://themes.googleusercontent.com/static/fonts/drsugiyama/v2/rq_8251Ifx6dE1Mq7bUM6brIa-7acMAeDBVuclsi6Gc.woff) format("woff");
}

body {
  font-family: sans-serif;
}
@media (min-width: 1000px) {
  body {
    font-family: 'Dr Sugiyama', sans-serif;
  }
}

Jordan Moore hat im Typekit Blog einen Artikel „Fallback Fonts on Mobile Devices“, der dieselbe Überlegung verwendet.

Ich habe diese Überlegung auf mein eigenes Projekt angewendet, indem ich zwei separate Schriftartensätze erstellt habe: einen „vollständigen“ Satz mit allen typografischen Stilen, die ich ursprünglich verwenden wollte, und einen „leichten“ Satz mit weniger Schriftarten (und dementsprechend deutlich geringerem Gewicht). Ich habe die Sätze per JavaScript geladen, abhängig von der Bildschirmbreite des Benutzers, wobei der Wert auf dem kleinsten Breakpoint basierte.

Mit Daves Technik müssten Sie sich keine Sorgen um FOUT (Flash of Unstyled Text) machen, da nativer @font-face-Code verwendet wird und die meisten Browser damit umgehen können. Jordans Technik wäre meiner Meinung nach stärker von FOUT betroffen, da die Schriftarten nach einem Test geladen werden müssten, aber Sie könnten das so beheben, wie Sie es immer mit Typekit beheben: mit visibility: hidden, während die Schriftarten geladen werden.

Schriftarten über Ajax laden

Wenn Ihr größtes Anliegen die Verlangsamung der Renderzeit ist (nicht unbedingt die Zeit bis zum vollständigen Laden der Seite), könnten Sie das Stylesheet, das den @font-face-Inhalt enthält, nach "document ready" über Ajax laden. Omar Al Zabir hat ein Tutorial dazu. (Danke Kevin)

$(document).ready(function(){
  $.ajax({
    url: fontFile,
    beforeSend: function ( xhr ) {
      xhr.overrideMimeType("application/octet-stream");
    },
    success: function(data) {
      $("<link />", {
        'rel': 'stylesheet'
        'href': 'URL/TO/fonts.css'
      }).appendTo('head');
    }
  });
});

Sicherzustellen, dass die Schriftartdateien "far expires headers" haben, ist ebenfalls wichtig. Um hier FOUT zu vermeiden, würden Sie der <html>-Element ein Klasse hinzufügen (sofort per JavaScript), die Sie verwenden, um das zu Verbergende mit visibility: hidden zu versehen, bis die Schriftarten geladen sind, und diese dann im Ajax-Erfolgs-Callback entfernen.

Schriftarten per Lazy Load laden, auf nachfolgenden Seitenaufrufen nach dem Caching laden

Diese Idee erweiternd könnten wir benutzerdefinierte Schriftarten nur anzeigen, wenn wir ziemlich sicher wären, dass die Schriftartdateien zwischengespeichert sind. Auf dem Backend prüfen wir auf ein Cookie (das wir später selbst setzen), das anzeigt, dass die Schriftarten zwischengespeichert sind.

// Check if cookie exists suggesting fonts are cached

if (fonts_are_cached) {
  echo "<link rel='stylesheet' href='/URL/TO/fonts.css'>";
}

Auf dem Frontend machen wir genau das Gegenteil. Wenn das Cookie nicht vorhanden ist, laden wir diese Schriftarten per Lazy Load und setzen dann das Cookie.

// Check if cookie exists suggesting fonts are cached

if (!fonts_are_cached) {

  // Don't slow down rendering
  $(window).load(function() {

    // Load in custom fonts
    $.ajax({
      url: 'URL/TO/font.woff'
    });
    $.ajax({
      url: 'URL/TO/font.eot'
    });
    // Don't actually do anything with them, just request them so they are cached.

    // Set cookie indicating fonts are cached

  });
  
}

Nicht narrensicher, da dieses Cookie nicht zu 100% beweist, dass die Schriftart zwischengespeichert ist. Aber wenn Sie es beispielsweise auf einen Tag Laufzeit setzen, hat es eine gute Chance. Keine FOUT hier, da entweder die Schriftarten gar nicht geladen werden oder nativ mit @font-face. Wenn Ihnen FOUT nichts ausmacht (d.h. Sie möchten Ihre benutzerdefinierte Schriftart beim ersten Seitenaufruf auf jeden Fall anzeigen), könnten Sie das <link>-Element erstellen und das Schriftarten-Stylesheet einfügen, anstatt nur die Schriftarten anzufordern.

Eine weitere Alternative wäre, eine Data-URI-Version der Schriftart in localStorage zu speichern und sie bei Bedarf abzurufen. Sie würden ein <style>-Element erstellen, den @font-face-Code darin einfügen und die Data-URI-Version der Schriftart verwenden und diese injizieren. Angeblich versucht The Guardian das.

Als faire Warnung: localStorage kann langsamer sein als der Cache.


Ein möglicher Vorteil der Verwendung von JavaScript-Tricks ist die Kenntnis der benötigten Schriftartversionen.

Und wie.

Die Zukunft

All dies wird besser, je mehr Informationen wir über die Situation des Clients erhalten können.

Welche Bandbreite und Latenz hat er? Das ist ziemlich schwer (und aufwendig) zu testen und selbst wenn wir es können, nicht sehr zuverlässig. Vielleicht hilft irgendwann die Network Information API.

Wie groß ist sein Bildschirm? Welche Fähigkeiten hat der Browser? Wir können dies per JavaScript testen, aber was, wenn es besser wäre, es serverseitig zu wissen? Vielleicht hilft irgendwann Client-Hints.