Layout-Instabilität beheben

Eine Schritt-für-Schritt-Anleitung zur Verwendung von WebPageTest zum Erkennen und Beheben von Layoutinstabilitätsproblemen

In einem früheren Beitrag habe ich über das Messen der Cumulative Layout Shift (CLS) in WebPageTest berichtet. CLS ist eine Zusammenfassung aller Layout Shifts. In diesem Beitrag dachte ich, es wäre interessant, die einzelnen Layout Shifts auf einer Seite genauer unter die Lupe zu nehmen, um die Ursache für die Instabilität zu finden und die Probleme zu beheben.

Layout Shifts messen

Mit der Layout Instability API können wir eine Liste aller Layout Shift-Ereignisse auf einer Seite abrufen:

new Promise(resolve => {
  new PerformanceObserver(list => {
    resolve(list.getEntries().filter(entry => !entry.hadRecentInput));
  }).observe({type: "layout-shift", buffered: true});
}).then(console.log);

Dies erzeugt ein Array von Layoutverschiebungen, denen keine Eingabeereignisse vorausgehen:

[
  {
    "name": "",
    "entryType": "layout-shift",
    "startTime": 210.78500000294298,
    "duration": 0,
    "value": 0.0001045969445437389,
    "hadRecentInput": false,
    "lastInputTime": 0
  }
]

In diesem Beispiel gab es eine einzige sehr winzige Verschiebung von 0,01% bei 210 ms.

Wenn Sie die Zeit und den Schweregrad der Änderung kennen, können Sie eingrenzen, was sie verursacht haben könnte. Kehren wir zu WebPageTest zurück, einer Lab-Umgebung, in der Sie weitere Tests durchführen können.

Layoutverschiebungen in WebPageTest messen

Ähnlich wie bei der CLS-Messung in WebPageTest ist für die Messung einzelner Layoutverschiebungen ein benutzerdefinierter Messwert erforderlich. Mit der stabilen Version von Chrome 77 ist dieser Vorgang zum Glück noch einfacher. Die Layout Instability API ist standardmäßig aktiviert. Sie sollten also in der Lage sein, dieses JS-Snippet auf jeder Website in Chrome 77 auszuführen und sofort Ergebnisse zu erhalten. In WebPageTest können Sie den Standardbrowser von Google Chrome verwenden, ohne sich um Befehlszeilen-Flags oder die Verwendung von Canary kümmern zu müssen.

Also ändern wir dieses Skript, um einen benutzerdefinierten Messwert für WebPageTest zu erstellen:

[LayoutShifts]
return new Promise(resolve => {
  new PerformanceObserver(list => {
    resolve(JSON.stringify(list.getEntries().filter(entry => !entry.hadRecentInput)));
  }).observe({type: "layout-shift", buffered: true});
});

Das Promise in diesem Skript wird in eine JSON-Darstellung des Arrays aufgelöst, nicht in das Array selbst. Das liegt daran, dass benutzerdefinierte Messwerte nur primitive Datentypen wie Strings oder Zahlen erzeugen können.

Für den Test verwende ich die Website ismyhostfastyet.com. Diese Website wurde erstellt, um die Ladeleistung von Webhosts in der realen Welt zu vergleichen.

Ursachen für Layout-Instabilität identifizieren

In den Ergebnissen sehen wir, dass der benutzerdefinierte Messwert „LayoutShifts“ folgenden Wert hat:

[
  {
    "name": "",
    "entryType": "layout-shift",
    "startTime": 3087.2349999990547,
    "duration": 0,
    "value": 0.3422101449275362,
    "hadRecentInput": false,
    "lastInputTime": 0
  }
]

Zusammenfassend lässt sich sagen, dass in 3.087 ms ein einzelner Layout Shift von 34,2% stattfindet. Um den Fehler zu finden, verwenden wir die Filmstreifenansicht von WebPageTest.

Zwei Zellen im Filmstreifen mit Screenshots vor und nach dem Layout Shift.
Zwei Zellen im Filmstreifen mit Screenshots vor und nach dem Layout Shift

Wenn Sie im Filmstreifen zur 3-Sekunden-Marke scrollen, sehen wir genau die Ursache der 34-%-Layoutverschiebung: die bunte Tabelle. Die Website ruft eine JSON-Datei asynchron ab und rendert sie in eine Tabelle. Die Tabelle ist anfänglich leer, sodass die Verschiebung auftritt, wenn sie erst nach dem Laden der Ergebnisse gefüllt ist.

Kopfzeile der Webschriftart, die plötzlich erscheint.
Webschriftart-Header, der aus dem Nichts erscheint.

Aber das ist noch nicht alles! Wenn die Seite nach etwa 4,3 Sekunden visuell vollständig ist, können wir aus dem Nichts das <h1> der Seite „Is my host fast already?“ sehen. Das liegt daran, dass auf der Website eine Webschriftart verwendet und keine Maßnahmen zur Optimierung des Renderings ergriffen wurden. Das Layout scheint sich in diesem Fall nicht zu verschieben, aber es ist immer noch frustrierend, so lange auf das Lesen des Titels warten zu müssen.

Layout-Instabilität beheben

Da wir nun wissen, dass die asynchron generierte Tabelle dazu führt, dass sich ein Drittel des Darstellungsbereichs verschiebt, ist es an der Zeit, das Problem zu beheben. Der Inhalt der Tabelle wird erst erkannt, wenn die JSON-Ergebnisse tatsächlich geladen wurden. Wir können die Tabelle dennoch mit Platzhalterdaten füllen, sodass das Layout selbst relativ stabil ist, wenn das DOM gerendert wird.

Hier ist der Code zum Generieren von Platzhalterdaten:

function getRandomFiller(maxLength) {
  var filler = '█';
  var len = Math.ceil(Math.random() * maxLength);
  return new Array(len).fill(filler).join('');
}

function getRandomDistribution() {
  var fast = Math.random();
  var avg = (1 - fast) * Math.random();
  var slow = 1 - (fast + avg);
  return [fast, avg, slow];
}

// Temporary placeholder data.
window.data = [];
for (var i = 0; i < 36; i++) {
  var [fast, avg, slow] = getRandomDistribution();
  window.data.push({
    platform: getRandomFiller(10),
    client: getRandomFiller(5),
    n: getRandomFiller(1),
    fast,
    avg,
    slow
  });
}
updateResultsTable(sortResults(window.data, 'fast'));

Die Platzhalterdaten werden zufällig generiert, bevor sie sortiert werden. Das Zeichen „█“ wird zufällig oft wiederholt, um visuelle Platzhalter für den Text und eine zufällig generierte Verteilung der drei Hauptwerte zu erstellen. Ich habe auch einige Stile hinzugefügt, um alle Farben aus der Tabelle zu entsättigen, um zu verdeutlichen, dass die Daten noch nicht vollständig geladen sind.

Das Erscheinungsbild der von Ihnen verwendeten Platzhalter spielt für die Stabilität des Layouts keine Rolle. Die Platzhalter sollen Nutzern versichern, dass die Inhalte einkommen und die Seite nicht fehlerhaft ist.

So sehen die Platzhalter aus, während die JSON-Daten geladen werden:

Die Datentabelle wird mit Platzhalterdaten gerendert.
Die Datentabelle wird mit Platzhalterdaten gerendert.

Die Behebung des Problems mit Webschriftarten ist viel einfacher. Da die Website Google Fonts verwendet, müssen wir nur die Eigenschaft display=swap in der CSS-Anfrage übergeben. Das ist alles. Die Fonts API fügt der Schriftartdeklaration den Stil font-display: swap hinzu, sodass der Browser Text sofort in einer Fallback-Schriftart rendern kann. Hier ist das entsprechende Markup mit der Korrektur:

<link href="https://fonts.googleapis.com/css?family=Chivo:900&display=swap" rel="stylesheet">

Optimierungen überprüfen

Nachdem die Seite mit WebPageTest erneut ausgeführt wurde, können wir einen Vorher-Nachher-Vergleich generieren, um den Unterschied zu visualisieren und den neuen Grad der Layoutinstabilität zu messen:

WebPageTest-Filmstreifen mit beiden Seiten, die nebeneinander mit und ohne Layoutoptimierungen geladen werden
WebPageTest-Filmstreifen mit Seiten, die nebeneinander mit und ohne Layoutoptimierungen geladen werden
[
  {
    "name": "",
    "entryType": "layout-shift",
    "startTime": 3070.9349999997357,
    "duration": 0,
    "value": 0.000050272187989256116,
    "hadRecentInput": false,
    "lastInputTime": 0
  }
]

Gemäß dem benutzerdefinierten Messwert kommt es immer noch zu einer Layoutverschiebung bei 3.071 ms (ungefähr genauso lange wie zuvor), aber der Schweregrad der Verschiebung ist viel kleiner: 0,005%. Ich kann damit leben.

Aus dem Filmstreifen geht auch hervor, dass die Schriftart <h1> sofort zu einer Systemschrift wechselt, damit Nutzer sie schneller lesen können.

Fazit

Bei komplexen Websites werden wahrscheinlich deutlich mehr Layoutverschiebungen auftreten als in diesem Beispiel, aber der Prozess ist immer noch der gleiche: Fügen Sie WebPageTest Messwerte für Layout-Instabilität hinzu, vergleichen Sie die Ergebnisse mit dem visuellen Ladestreifen, um die Täter zu identifizieren, und implementieren Sie eine Korrektur mithilfe von Platzhaltern, um Platz auf dem Bildschirm zu reservieren.

Und noch etwas: Das Messen der Layout-Instabilität bei echten Nutzern

Es ist toll, WebPageTest vor und nach einer Optimierung auf einer Seite ausführen und eine Verbesserung der Messwerte feststellen zu können. Entscheidend ist jedoch, dass die Nutzererfahrung tatsächlich verbessert wird. Ist das nicht der Grund, warum wir die Website nicht von vornherein verbessern wollen?

Es wäre toll, wenn wir die Layoutinstabilität echter Nutzer zusammen mit unseren herkömmlichen Messwerten zur Webleistung messen würden. Dies ist ein entscheidender Teil der Feedback-Schleife für die Optimierung, da uns die Daten aus diesem Bereich zeigen, wo die Probleme liegen und ob unsere Korrekturen einen positiven Unterschied gemacht haben.

Zusätzlich zu Ihren eigenen Daten zur Instabilität beim Layout sollten Sie sich auch den UX-Bericht für Chrome ansehen. Dieser enthält Daten zur Cumulative Layout Shift aus der Nutzerfreundlichkeit auf Millionen von Websites. Sie können damit herausfinden, wie Sie (oder Ihre Mitbewerber) abschneiden, oder den Zustand der Layout-Instabilität im Web untersuchen.