Eine Fallstudie zur Verbesserung der Front-End-Performance

Avatar of Declan Rek
Declan Rek am

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

Bei De Voorhoede versuchen wir, die Front-End-Performance für unsere Kunden so weit wie möglich zu steigern. Es ist nicht einfach, jeden Kunden davon zu überzeugen, alle unsere Performance-Richtlinien zu befolgen. Wir versuchen, sie zu überzeugen, indem wir in ihrer Sprache sprechen und die Bedeutung von Performance für die Konversion erklären oder ihre Performance mit der ihrer Hauptkonkurrenten vergleichen.

Nebenbei haben wir kürzlich unsere Website aktualisiert. Abgesehen von einer kompletten Überarbeitung des Designs war dies die ideale Gelegenheit, die Performance auf das Maximum zu pushen. Unser Ziel war es, die Kontrolle zu übernehmen, uns auf die Performance zu konzentrieren, flexibel für die Zukunft zu sein und das Schreiben von Inhalten für unsere Website unterhaltsam zu gestalten. Hier erfahren Sie, wie wir die Front-End-Performance für unsere Website gemeistert haben. Viel Spaß!

Design für Performance

In unseren Projekten führen wir tägliche Diskussionen mit Designern und Produktverantwortlichen über die Balance zwischen Ästhetik und Performance. Für unsere eigene Website war das einfach. Wir glauben, dass eine gute Benutzererfahrung damit beginnt, Inhalte so schnell wie möglich bereitzustellen. Das bedeutet Performance > Ästhetik.

Gute Inhalte, Layouts, Bilder und Interaktivität sind für die Einbindung Ihres Publikums unerlässlich, aber jedes dieser Elemente hat Auswirkungen auf die Ladezeit der Seite und das Endnutzererlebnis. Bei jedem Schritt haben wir überlegt, wie wir eine gute Benutzererfahrung und ein schönes Design erzielen und gleichzeitig minimale Auswirkungen auf die Performance haben können.

Inhalt zuerst

Wir möchten unseren Besuchern den Kerninhalt (Text mit dem wesentlichen HTML und CSS) so schnell wie möglich zur Verfügung stellen. Jede Seite sollte dem primären Zweck des Inhalts dienen: die Botschaft zu vermitteln. Erweiterungen, d. h. JavaScript, vollständiges CSS, Webfonts, Bilder und Analysen, sind dem Kerninhalt untergeordnet.

Kontrolle übernehmen

Nachdem wir die Standards für unsere ideale Website definiert hatten, kamen wir zu dem Schluss, dass wir die volle Kontrolle über jeden Aspekt der Website benötigen. Wir entschieden uns, unseren eigenen statischen Website-Generator zu entwickeln, einschließlich einer Asset-Pipeline, und ihn selbst zu hosten.

Statischer Website-Generator

Wir haben unseren eigenen statischen Website-Generator in Node.js geschrieben. Er nimmt Markdown-Dateien mit kurzen JSON-Seiten-Metabeschreibungen entgegen, um die gesamte Website-Struktur mit all ihren Assets zu generieren. Er kann auch von einer HTML-Datei zur Einbindung von Seitenspezifischem JavaScript begleitet werden.

Unten sehen Sie eine vereinfachte Metabeschreibung und eine Markdown-Datei für einen Blogbeitrag, die zur Generierung des tatsächlichen HTML verwendet werden.

Die JSON-Metabeschreibung

{
  "keywords": ["performance", "critical rendering path", "static site", "..."],
  "publishDate": "2016-08-12",
  "authors": ["Declan"]
}

Und die Markdown-Datei

# A case study on boosting front-end performance
At [De Voorhoede](https://www.voorhoede.nl/en/) we try to boost front-end performance...

## Design for performance

In our projects we have daily discussions...

Bildlieferung

Die durchschnittliche Webseite ist satte 2406 KB, davon 1535 KB Bilder. Da Bilder einen so großen Teil der durchschnittlichen Website ausmachen, sind sie auch eines der besten Ziele für Performance-Gewinne.

Durchschnittliche Bytes pro Seite nach Inhaltstyp für Juli 2016 von httparchive.org

WebP

WebP ist ein modernes Bildformat, das eine überlegene verlustfreie und verlustbehaftete Komprimierung für Bilder im Web bietet. WebP-Bilder können erheblich kleiner sein als Bilder in anderen Formaten: manchmal sind sie bis zu 25 % kleiner als ihr JPEG-Gegenstück. WebP wird oft übersehen und nicht oft verwendet. Zum Zeitpunkt des Schreibens wird WebP nur von Chrome, Opera und Android unterstützt (immer noch über 50 % unserer Nutzer), aber wir können bei Bedarf elegant auf JPG/PNG zurückgreifen.

<picture>-Element

Mit dem picture-Element können wir elegant von WebP auf ein weiter verbreitetes Format wie JPEG zurückgreifen.

<picture>
  <source type="image/webp" srcset="image-l.webp" media="(min-width: 640px)">
  <source type="image/webp" srcset="image-m.webp" media="(min-width: 320px)">
  <source type="image/webp" srcset="image-s.webp">
  <source srcset="image-l.jpg" media="(min-width: 640px)">
  <source srcset="image-m.jpg" media="(min-width: 320px)">
  <source srcset="image-s.jpg">
  <img alt="Description of the image" src="image-l.jpg">
</picture>

Wir verwenden picturefill von Scott Jehl, um Browser zu polyfillen, die das <picture>-Element nicht unterstützen, und um ein konsistentes Verhalten über alle Browser hinweg zu erzielen.

Wir verwenden das <img>-Element als Fallback für Browser, die das <picture>-Element und/oder JavaScript nicht unterstützen. Die Verwendung der größten Instanz des Bildes stellt sicher, dass es auch im Fallback-Szenario gut aussieht.

Generate

Während der Ansatz zur Bildlieferung vorhanden war, mussten wir noch herausfinden, wie wir ihn schmerzlos implementieren können. Ich liebe das picture-Element für das, was es kann, aber ich hasse es, den obigen Schnipsel zu schreiben. Besonders, wenn ich ihn beim Schreiben von Inhalten einbeziehen muss. Wir wollen uns nicht mit der Generierung von 6 Instanzen jedes Bildes, der Optimierung der Bilder und dem Schreiben von <picture>-Elementen in unserem Markdown befassen. Also haben wir

  • generieren mehrere Instanzen der Originalbilder in unserem Build-Prozess, sowohl im Eingabeformat (JPG, PNG) als auch in WebP. Wir verwenden gulp responsive dafür.
  • minimieren die generierten Bilder
  • schreiben ![Beschreibung des Bildes](http://placehold.it/350x150.png) in unseren Markdown-Dateien.
  • verwenden benutzerdefinierte Markdown-Renderer während des Build-Prozesses, um konventionelle Markdown-Bilddeklarationen in vollwertige <picture>-Elemente zu **kompilieren**.

SVG-Animationen

Wir haben einen eigenständigen Grafikstil für unsere Website gewählt, bei dem SVG-Illustrationen eine wichtige Rolle spielen. Dies haben wir aus mehreren Gründen getan.

  • Erstens sind SVGs (Vektorbilder) tendenziell kleiner als Bitmap-Bilder;
  • Zweitens sind SVGs von Natur aus reaktionsfähig und skalieren perfekt, während sie immer gestochen scharf bleiben. Kein Bedarf mehr an Bildgenerierung und <picture>-Elementen;
  • Zu guter Letzt können wir sie mit CSS animieren und verändern! Ein perfektes Beispiel für Design für Performance. Alle unsere Portfolioseiten haben eine individuell gestaltete animierte SVG, die auf der Übersichtsseite wiederverwendet wird. Sie dient als wiederkehrender Stil für alle unsere Portfolioelemente, was das Design konsistent macht und nur geringe Auswirkungen auf die Performance hat.

Schauen Sie sich diese Animation an und wie wir sie mit CSS verändern können.

Siehe den Pen Ändern Sie die Inline-SVG-Stile von De Voorhoede (@voorhoede) auf CodePen.

Benutzerdefinierte Webfonts

Bevor wir eintauchen, hier eine kurze Einführung in das Verhalten von Browsern in Bezug auf benutzerdefinierte Webfonts. Wenn der Browser auf eine @font-face-Definition in CSS stößt, die auf eine Schriftart verweist, die nicht auf dem Computer des Benutzers verfügbar ist, versucht er, diese Schriftartdatei herunterzuladen. Während des Downloads zeigt der Browser den Text mit dieser Schriftart meist nicht an. Gar nicht. Dieses Phänomen wird als "Flash of Invisible Text" oder FOIT bezeichnet. Wenn Sie wissen, wonach Sie suchen müssen, werden Sie es fast überall im Web finden. Und wenn Sie mich fragen, ist es schlecht für das Endnutzererlebnis. Es verzögert den Benutzer bei der Erreichung seines Kernziels: das Lesen des Inhalts.

Wir können den Browser jedoch zwingen, sein Verhalten in ein "Flash of Unstyled Content" oder FOUT zu ändern. Wir weisen den Browser an, zunächst eine allgegenwärtige Schriftart wie Arial oder Georgia zu verwenden. Sobald die benutzerdefinierte Webfont heruntergeladen ist, ersetzt sie die Standardschriftart und rendert den gesamten Text neu. Wenn die benutzerdefinierte Schriftart nicht geladen werden kann, ist der Inhalt immer noch perfekt lesbar. Während einige dies als Fallback betrachten mögen, sehen wir benutzerdefinierte Schriften als Verbesserung. Selbst ohne sie sieht die Website gut aus und funktioniert zu 100 %.

Links ein Blogbeitrag mit der benutzerdefinierten Webfont, rechts ein Blogbeitrag mit unserer "Fallback"-Schriftart.

Die Verwendung benutzerdefinierter Webfonts kann das Benutzererlebnis verbessern, solange Sie sie optimieren und verantwortungsvoll bereitstellen.

Schriftart-Subsetting

Subsetting ist mit Abstand der schnellste Weg zur Verbesserung der Webfont-Performance. Ich würde es jedem Webentwickler empfehlen, der benutzerdefinierte Schriftarten verwendet. Sie können beim Subsetting alles geben, wenn Sie die vollständige Kontrolle über den Inhalt haben und wissen, welche Zeichen angezeigt werden. Aber selbst das Subsetting Ihrer Schriftart auf "westliche Sprachen" hat einen enormen Einfluss auf die Dateigröße. Zum Beispiel verringert sich unsere Noto Regular WOFF-Schriftart, die standardmäßig 246 KB groß ist, auf 31 KB, wenn sie auf westliche Sprachen gesubsettet wird. Wir haben den Font Squirrel Webfont-Generator verwendet, der wirklich einfach zu bedienen ist.

Font Face Observer

Font face observer von Bram Stein ist ein großartiges Hilfsskript, um zu überprüfen, ob Schriftarten geladen sind. Es ist unabhängig davon, wie Sie Ihre Schriftarten laden, sei es über einen Webfont-Dienst oder durch Selbst-Hosting. Nachdem das Font Face Observer-Skript uns benachrichtigt hat, dass alle benutzerdefinierten Webfonts geladen sind, fügen wir dem <html>-Element eine Klasse fonts-loaded hinzu. Wir stylen unsere Seiten entsprechend.

html {
  font-family: Georgia, serif;
}

html.fonts-loaded {
  font-family: Noto, Georgia, serif;
}

Hinweis: Aus Gründen der Kürze habe ich die @font-face-Deklaration für Noto im obigen CSS nicht aufgenommen.

Wir setzen auch einen Cookie, um uns daran zu erinnern, dass alle Schriftarten geladen sind und sich daher im Cache des Browsers befinden. Wir verwenden diesen Cookie für wiederholte Aufrufe, was ich später erklären werde.

In naher Zukunft werden wir Bram Steins JavaScript wahrscheinlich nicht mehr benötigen, um dieses Verhalten zu erreichen. Die CSS Working Group hat einen neuen @font-face-Deskriptor (genannt font-display) vorgeschlagen, bei dem der Wert der Eigenschaft steuert, wie eine herunterladbare Schriftart vor dem vollständigen Laden gerendert wird. Die CSS-Anweisung font-display: swap; würde uns das gleiche Verhalten wie der obige Ansatz bieten. Lesen Sie mehr über die font-display-Eigenschaft.

Lazy Load JS und CSS

Generell verfolgen wir einen Ansatz, Assets so schnell wie möglich zu laden. Wir eliminieren Render-Blocking-Anfragen und optimieren für die erste Ansicht, wobei wir den Browser-Cache für wiederholte Ansichten nutzen.

Lazy Load JS

Konzeptionell haben wir nicht viel JavaScript auf unserer Website. Für das, was wir haben, und was wir in Zukunft verwenden wollen, haben wir einen JavaScript-Workflow entwickelt.

JavaScript im <head> blockiert das Rendering, und das wollen wir nicht. JavaScript sollte nur die Benutzererfahrung verbessern; es ist für unsere Besucher nicht kritisch. Der einfache Weg, Render-Blocking-JavaScript zu beheben, ist, das Skript am Ende Ihrer Webseite zu platzieren. Der Nachteil ist, dass der Download des Skripts erst beginnt, nachdem das gesamte HTML heruntergeladen wurde.

Eine Alternative könnte sein, das Skript in den Head einzufügen und die Skriptausführung zu verzögern, indem Sie das defer-Attribut zum <script>-Tag hinzufügen. Dies macht das Skript nicht-blockierend, da der Browser es fast sofort herunterlädt, ohne den Code auszuführen, bis die Seite geladen ist.

Es bleibt nur noch eines zu erwähnen: Wir verwenden keine Bibliotheken wie jQuery, und daher hängt unser JavaScript von nativen JavaScript-Funktionen ab. Wir möchten JavaScript nur in Browsern laden, die diese Funktionen unterstützen (d. h. Mustard Cutting). Das Endergebnis sieht so aus:

<script>
// Mustard Cutting
if ('querySelector' in document && 'addEventListener' in window) {
  document.write('<script src="index.js" defer><\/script>');
}
</script>

Wir platzieren dieses kleine Inline-Skript im Head unserer Seite, das erkennt, ob die nativen JavaScript-Funktionen document.querySelector und window.addEventListener unterstützt werden. Wenn ja, laden wir das Skript, indem wir das script-Tag direkt auf die Seite schreiben, und verwenden das defer-Attribut, um es nicht-blockierend zu machen.

Lazy Load CSS

Für die erste Ansicht ist die größte Render-Blocking-Ressource für unsere Website CSS. Browser verzögern das Rendern der Seite, bis die vollständige CSS-Datei, auf die im <head> verwiesen wird, heruntergeladen und geparst ist. Dieses Verhalten ist beabsichtigt, da der Browser sonst Layouts und Neudrucke während des Renderns ständig neu berechnen müsste.

Um zu verhindern, dass CSS das Rendering blockiert, müssen wir die CSS-Datei asynchron laden. Wir verwenden die großartige loadCSS-Funktion von Filament Group. Sie gibt uns einen Callback, wenn die CSS-Datei geladen ist, und wir setzen dann einen Cookie, der besagt, dass das CSS geladen ist. Diesen Cookie verwenden wir für wiederholte Aufrufe, was ich später erklären werde.

Beim asynchronen Laden von CSS gibt es ein "Problem": Während das HTML sehr schnell gerendert wird, sieht es wie reines HTML ohne angewendetes CSS aus, bis das vollständige CSS heruntergeladen und geparst ist. Hier kommt Critical CSS ins Spiel.

Critical CSS

Critical CSS kann als die minimale Menge an blockierendem CSS beschrieben werden, um eine Seite für den Benutzer erkennbar erscheinen zu lassen. Wir konzentrieren uns auf Inhalte "above the fold" (oberhalb des sichtbaren Bereichs). Offensichtlich variiert die Position des Falzes je nach Gerät stark, daher machen wir eine bestmögliche Schätzung.

Die manuelle Bestimmung dieses kritischen CSS ist ein zeitaufwändiger Prozess, insbesondere bei zukünftigen Stiländerungen. Es gibt mehrere nützliche Skripte zur Generierung von Critical CSS in Ihrem Build-Prozess. Wir haben das prächtige critical npm-Modul von Addy Osmani verwendet.

Sehen Sie unten unsere Homepage, gerendert mit Critical CSS und gerendert mit dem vollständigen CSS. Beachten Sie den Fold, unter dem die Seite immer noch etwas ungestaltet ist.

Links die Homepage, gerendert nur mit Critical CSS, rechts die Homepage, gerendert mit dem vollständigen CSS. Die rote Linie stellt den Fold dar.

Der Server

Wir hosten die Website von De Voorhoede selbst, da wir die Kontrolle über die Serverumgebung haben wollten. Wir wollten auch experimentieren, wie wir die Performance durch Änderung der Serverkonfiguration steigern können. Derzeit haben wir einen Apache-Webserver und servieren unsere Website über HTTPS.

Konfiguration

Um Performance und Sicherheit zu steigern, haben wir uns etwas recherchiert, wie wir den Server konfigurieren können.

Wir verwenden die H5BP Boilerplate Apache-Konfiguration, die ein guter Ausgangspunkt für die Verbesserung von Performance und Sicherheit für Ihren Apache-Webserver ist. Sie haben auch Konfigurationen für andere Serverumgebungen.

Wir haben GZIP für die meisten unserer HTML-, CSS- und JavaScript-Dateien aktiviert. Wir haben Caching-Header für alle unsere Ressourcen sorgfältig eingestellt. Lesen Sie dazu weiter unten im Abschnitt Dateiebene-Caching.

HTTPS

Das Ausliefern Ihrer Website über HTTPS kann Auswirkungen auf die Performance Ihrer Website haben. Die Leistungseinbuße liegt hauptsächlich in der Einrichtung des SSL-Handshakes, was zu viel Latenz führt. Aber – wie immer – können wir etwas dagegen tun!

HTTP Strict Transport Security ist ein HTTP-Header, mit dem der Server dem Browser mitteilen kann, dass er nur über HTTPS kommunizieren soll. So werden HTTP-Anfragen daran gehindert, zu HTTPS weitergeleitet zu werden. Alle Versuche, auf die Website über HTTP zuzugreifen, sollten automatisch umgewandelt werden. Das spart uns einen Roundtrip!

TLS False Start ermöglicht es dem Client, verschlüsselte Daten sofort nach dem ersten TLS-Roundtrip zu senden. Diese Optimierung reduziert den Handshake-Overhead für neue TLS-Verbindungen auf einen Roundtrip. Sobald der Client den Verschlüsselungsschlüssel kennt, kann er mit der Übertragung von Anwendungsdaten beginnen. Der Rest des Handshakes dient der Bestätigung, dass niemand die Handshake-Datensätze manipuliert hat, und kann parallel erfolgen.

TLS Session Resumption spart uns einen weiteren Roundtrip, indem sichergestellt wird, dass der Browser und der Server, wenn sie bereits über TLS kommuniziert haben, den Sitzungsidentifikator wiederverwenden können. Beim nächsten Aufbau einer Verbindung kann dieser Identifikator wiederverwendet werden, was einen Roundtrip spart.

Ich klinge wie ein DevOps-Ingenieur, aber das bin ich nicht. Ich habe nur einige Dinge gelesen und Videos gesehen. Ich habe Mythbusting HTTPS: Squashing security’s urban legends von Emily Stark von Google I/O 2016 geliebt.

Verwendung von Cookies

Wir haben keine serverseitige Sprache, nur einen statischen Apache-Webserver. Aber ein Apache-Webserver kann immer noch Server-Side Includes (SSI) durchführen und Cookies auslesen. Durch kluge Nutzung von Cookies und das Ausliefern von HTML, das teilweise von Apache neu geschrieben wird, können wir die Front-End-Performance steigern. Nehmen Sie dieses Beispiel unten (unser tatsächlicher Code ist etwas komplexer, aber es läuft auf dieselben Ideen hinaus)

<!-- #if expr="($HTTP_COOKIE!=/css-loaded/) || ($HTTP_COOKIE=/.*css-loaded=([^;]+);?.*/ && ${1} != '0d82f.css' )"-->

<noscript><link rel="stylesheet" href="0d82f.css"></noscript>
<script>
(function() {
  function loadCSS(url) {...}
  function onloadCSS(stylesheet, callback) {...}
  function setCookie(name, value, expInDays) {...}

  var stylesheet = loadCSS('0d82f.css');
  onloadCSS(stylesheet, function() {
    setCookie('css-loaded', '0d82f', 100);
  });
}());
</script>

<style>/* Critical CSS here */</style>

<!-- #else -->
<link rel="stylesheet" href="0d82f.css">
<!-- #endif -->

Die serverseitige Apache-Logik sind die kommentarähnlichen Zeilen, die mit <!-- # beginnen. Betrachten wir dies Schritt für Schritt:

  • $HTTP_COOKIE!=/css-loaded/ prüft, ob noch kein CSS-Cache-Cookie existiert.
  • $HTTP_COOKIE=/.*css-loaded=([^;]+);?.*/ && ${1} != '0d82f.css' prüft, ob die gecachte CSS-Version nicht die aktuelle Version ist.
  • Wenn <!-- #if expr="..." --> zu true ausgewertet wird, gehen wir davon aus, dass dies die erste Ansicht des Besuchers ist.
  • Für die erste Ansicht fügen wir einen <noscript>-Tag mit einem Render-Blocking <link rel="stylesheet"> hinzu. Dies tun wir, weil wir das vollständige CSS asynchron mit JavaScript laden werden. Wenn JavaScript deaktiviert wäre, wäre dies nicht möglich. Das bedeutet, dass wir als Fallback CSS "nach Zahlen" laden, d.h. blockierend.
  • Wir fügen ein Inline-Skript mit Funktionen zum Lazy Loading von CSS, einen onloadCSS-Callback und setzen Cookies.
  • Im selben Skript laden wir das vollständige CSS asynchron.
  • Im onloadCSS-Callback setzen wir einen Cookie mit dem Version-Hash als Cookie-Wert.
  • Nach dem Skript fügen wir ein Inline-Stylesheet mit dem Critical CSS hinzu. Dies wird Render-Blocking sein, aber es wird sehr klein sein und verhindern, dass die Seite als reines, ungestaltetes HTML angezeigt wird.
  • Die <!-- #else -->-Anweisung (was bedeutet, dass das css-loaded-Cookie **vorhanden ist**) repräsentiert die wiederholten Ansichten des Besuchers. Da wir bis zu einem gewissen Grad davon ausgehen können, dass die CSS-Datei zuvor geladen wurde, können wir den Browser-Cache nutzen und das Stylesheet blockierend ausliefern. Es wird aus dem Cache geladen und lädt fast sofort.

Der gleiche Ansatz wird verwendet, um Schriftarten für die erste Ansicht asynchron zu laden, wobei davon ausgegangen wird, dass wir sie bei wiederholten Ansichten aus dem Browser-Cache liefern können.

Sehen Sie hier unsere Cookies, die verwendet werden, um zwischen der ersten und wiederholten Ansicht zu unterscheiden.

Dateiebene-Caching

Da wir uns stark auf Browser-Caching für wiederholte Ansichten verlassen, müssen wir sicherstellen, dass wir richtig cachen. Idealerweise möchten wir Assets (CSS, JS, Fonts, Bilder) für immer cachen und den Cache nur ungültig machen, wenn sich eine Datei tatsächlich ändert. Der Cache wird ungültig gemacht, wenn die Anfrageressource eindeutig ist. Wir verwenden git tag für unsere Website, wenn wir eine neue Version veröffentlichen. Der einfachste Weg wäre also, einen Query-Parameter zu den Anfrageressourcen mit der Codebasis-Version hinzuzufügen, wie z. B. `https://www.voorhoede.nl/assets/css/main.css?v=1.0.4`. Aber.

Der Nachteil dieses Ansatzes ist, dass bei einem neuen Blogbeitrag (der Teil unserer Codebasis ist, nicht extern in einem CMS gespeichert) der Cache für alle unsere Assets ungültig gemacht wird, obwohl keine Änderungen an diesen Assets vorgenommen wurden.

Bei dem Versuch, unseren Ansatz zu verbessern, sind wir auf gulp-rev und gulp-rev-replace gestoßen. Diese Skripte halfen uns, eine Revisionierung pro Datei hinzuzufügen, indem wir unseren Dateinamen einen Content-Hash anhängen. Das bedeutet, dass sich die Anfrageressource nur ändert, wenn die tatsächliche Datei geändert wurde. Jetzt haben wir eine Cache-Invalidierung pro Datei. Das lässt mein Herz höher schlagen!

Ergebnis

Wenn Sie es bis hierher geschafft haben (großartig!), möchten Sie wahrscheinlich das Ergebnis wissen. Das Testen der Performance Ihrer Website kann mit Tools wie PageSpeed Insights für sehr praktische Tipps und WebPagetest für umfassende Netzwerkanalysen erfolgen. Ich denke, der beste Weg, Ihre Rendering-Performance zu testen, ist, Ihre Seite beim Drosseln Ihrer Verbindung wahnsinnig werden zu sehen. Das bedeutet: Drosseln in einer wahrscheinlich unrealistischen Weise. In Google Chrome können Sie Ihre Verbindung drosseln (über den Inspektor > Netzwerk-Tab) und sehen, wie Anfragen langsam geladen werden, während Ihre Seite aufgebaut wird.

Sehen Sie also hier, wie unsere Homepage auf einer gedrosselten GPRS-Verbindung von 50 KB/s lädt.

Netzwerkanalyse für die Website und wie sich die Seite beim ersten Besuch entwickelt.

Beachten Sie, wie wir den ersten Render bei 2,27 s auf einem 50 KB/s GPRS-Netzwerk erhalten, dargestellt durch das erste Bild aus dem Filmstreifen und die entsprechende gelbe Linie in der Wasserfallansicht. Die gelbe Linie wird direkt nach dem Download des HTML gezeichnet. Das HTML enthält das Critical CSS, das sicherstellt, dass die Seite brauchbar aussieht. Alle anderen blockierenden Ressourcen werden lazy geladen, sodass wir mit der Seite interagieren können, während der Rest heruntergeladen wird. Das ist genau das, was wir wollten!

Eine weitere Sache, die Sie bemerken sollten, ist, dass benutzerdefinierte Schriftarten bei so langsamen Verbindungen nie geladen werden. Der Font Face Observer kümmert sich automatisch darum, aber wenn wir die Schriftarten nicht asynchron laden würden, würden Sie in den meisten Browsern eine Weile auf FOIT starren.

Die vollständige CSS-Datei wird erst nach 8 Sekunden geladen. Umgekehrt, wenn wir das vollständige CSS blockierend laden würden, anstatt Critical CSS inline zu haben, würden wir 8 Sekunden lang auf eine weiße Seite starren.

Wenn Sie neugierig sind, wie sich diese Zeiten mit anderen Websites vergleichen, die sich weniger auf die Performance konzentrieren, nur zu. Die Ladezeiten werden durch die Decke gehen!

Der Test unserer Website gegen die zuvor erwähnten Tools zeigt ebenfalls einige schöne Ergebnisse. PageSpeed Insights gibt uns eine 100/100-Bewertung für die mobile Performance, wie großartig ist das denn?!

Wenn wir uns WebPagetest ansehen, erhalten wir das folgende Ergebnis:

WebPagetest-Ergebnisse für voorhoede.nl.

Wir können sehen, dass unser Server gut funktioniert und der SpeedIndex für die erste Ansicht 693 beträgt. Das bedeutet, dass unsere Seite nach 693 ms über eine Kabelverbindung nutzbar ist. Sieht gut aus!

Roadmap

Wir sind noch nicht fertig und entwickeln unseren Ansatz ständig weiter. In naher Zukunft werden wir uns auf Folgendes konzentrieren:

  • HTTP/2: Es ist da und wir experimentieren gerade damit. Viele der in diesem Artikel beschriebenen Dinge sind bewährte Praktiken, die auf den Einschränkungen von HTTP/1.1 basieren. Kurz gesagt: HTTP/1.1 stammt aus dem Jahr 1999, als Tabellenlayouts und Inline-Styles super angesagt waren. HTTP/1.1 war nie für 2,6 MB große Webseiten mit 200 Anfragen konzipiert. Um die Schmerzen unseres alten Protokolls zu lindern, verketten wir JS und CSS, binden kritisches CSS inline ein, verwenden Daten-URLs für kleine Bilder usw. Alles, um Anfragen zu sparen. Da HTTP/2 mehrere Anfragen parallel über dieselbe TCP-Verbindung ausführen kann, könnten diese Verkettungen und die Reduzierung von Anfragen sogar ein Antipattern sein. Wir werden zu HTTP/2 wechseln, sobald wir mit den Experimenten fertig sind.
  • Service Workers: Dies ist eine moderne Browser-JavaScript-API, die im Hintergrund läuft. Sie ermöglicht viele Funktionen, die für Websites bisher nicht verfügbar waren, wie z. B. Offline-Unterstützung, Push-Benachrichtigungen, Hintergrundsynchronisierung und mehr. Wir spielen mit Service Workers herum, müssen sie aber noch in unsere eigene Website integrieren. Ich garantiere Ihnen, wir werden es tun!
  • CDN: Wir wollten die Kontrolle behalten und haben die Website selbst gehostet. Ja, ja, und jetzt wollen wir zu einem CDN wechseln, um die Netzwerklatenz zu beseitigen, die durch die physische Entfernung zwischen Client und Server verursacht wird. Obwohl unsere Kunden hauptsächlich in den Niederlanden ansässig sind, möchten wir die weltweite Front-End-Community auf eine Weise erreichen, die widerspiegelt, was wir am besten können: Qualität, Leistung und die Weiterentwicklung des Webs.

Danke fürs Lesen! Besuchen Sie unsere Website, um das Endergebnis zu sehen. Haben Sie Kommentare oder Fragen? Lassen Sie es uns über Twitter wissen. Und wenn Sie gerne schnelle Websites bauen, warum schließen Sie sich uns nicht an?