Layout-Instabilität beheben

Eine Anleitung zur Verwendung von WebPageTest, um Probleme mit der Layoutstabilität zu identifizieren und zu beheben.

In einem früheren Beitrag habe ich Ihnen das Messen von Cumulative Layout Shift (CLS) in WebPageTest beschrieben. Die CLS ist eine Aggregation aller Layoutverschiebungen. In diesem Beitrag möchte ich daher genauer darauf eingehen und jede einzelne Layoutverschiebung auf einer Seite untersuchen, um herauszufinden, was die Instabilität verursachen könnte, und die Probleme zu beheben.

Layout Shifts messen

Mit der Layout Instability API können wir eine Liste aller Layoutverschiebungsereignisse 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 führt zu einer Reihe von Layoutänderungen, die nicht durch Eingabeereignisse ausgelöst werden:

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

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

Wenn Sie den Zeitpunkt und die Schwere der Abweichung kennen, können Sie eingrenzen, was die Ursache sein könnte. Kehren wir zu WebPageTest zurück, wo Sie in einer Lab-Umgebung weitere Tests durchführen können.

Layoutverschiebungen in WebPageTest messen

Ähnlich wie beim Erfassen des CLS in WebPageTest ist für die Messung einzelner Layoutverschiebungen ein benutzerdefinierter Messwert erforderlich. Glücklicherweise ist der Vorgang jetzt einfacher, da Chrome 77 stabil ist. Die Layout Instability API ist standardmäßig aktiviert. Sie sollten dieses JS-Snippet also auf jeder Website in Chrome 77 ausführen und sofort Ergebnisse erhalten können. In WebPageTest können Sie den Chrome-Standardbrowser verwenden und müssen sich keine Gedanken über Befehlszeilen-Flags oder Canary machen.

Ändern wir also dieses Skript, um einen benutzerdefinierten Messwert für WebPageTest zu generieren:

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

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

Die Website, die ich für den Test verwende, ist ismyhostfastyet.com. Ich habe sie entwickelt, um die tatsächliche Ladeleistung von Webhosts zu vergleichen.

Ursachen für Layoutinstabilität ermitteln

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

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

Zusammenfassend gibt es eine einzelne Layoutverschiebung von 34,2 % bei 3.087 ms. Um den Schuldigen zu ermitteln, verwenden wir die Filmstreifenansicht von WebPageTest.

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

Wenn wir im Filmstreifen zur 3-Sekunden-Marke scrollen, sehen wir genau, was die Ursache für die 34-prozentige Layoutverschiebung ist: die bunte Tabelle. Die Website ruft asynchron eine JSON-Datei ab und rendert sie dann in einer Tabelle. Die Tabelle ist anfangs leer. Wenn Sie also warten, bis sie beim Laden der Ergebnisse gefüllt ist, kommt es zu einer Verschiebung.

Webfont-Header erscheint aus dem Nichts.
Web-Schriftarten-Header, der aus dem Nichts erscheint

Aber das ist noch nicht alles! Wenn die Seite nach etwa 4,3 Sekunden optisch vollständig ist, sehen wir, dass das <h1> der Seite „Ist mein Host schon schnell?“ aus dem Nichts erscheint. Das liegt daran, dass auf der Website eine Webschrift verwendet wird und keine Maßnahmen zur Optimierung des Renderings ergriffen wurden. Das Layout scheint sich in diesem Fall nicht zu verschieben, aber es ist trotzdem ärgerlich, so lange warten zu müssen, bis man den Titel lesen kann.

Behebung von Layoutinstabilität

Da wir jetzt 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. Wir kennen den Inhalt der Tabelle erst, wenn die JSON-Ergebnisse tatsächlich geladen wurden. Wir können die Tabelle aber trotzdem mit einer Art Platzhalterdaten füllen, damit das Layout beim Rendern des DOM relativ stabil ist.

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. Es enthält das Zeichen „█“, das eine zufällige Anzahl von Malen wiederholt wird, um visuelle Platzhalter für den Text zu erstellen, und eine zufällig generierte Verteilung der drei Hauptwerte. Außerdem habe ich einige Stile hinzugefügt, um die gesamte Farbe aus der Tabelle zu entfernen, damit klar ist, dass die Daten noch nicht vollständig geladen sind.

Das Aussehen der verwendeten Platzhalter spielt für die Layoutstabilität keine Rolle. Die Platzhalter sollen Nutzern versichern, dass Inhalte kommen und die Seite nicht kaputt 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.

Das Problem mit Webschriften lässt sich viel einfacher beheben. Da auf der Website Google Fonts verwendet werden, müssen wir nur die Property display=swap in der CSS-Anfrage übergeben. Das ist alles. Die Fonts API fügt der Schriftartdeklaration den Stil font-display: swap hinzu, damit 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 wir die Seite noch einmal mit WebPageTest ausgeführt haben, können wir einen Vergleich vor und nach erstellen, um den Unterschied zu visualisieren und den neuen Grad der Layoutinstabilität zu messen:

WebPageTest-Filmstreifen, auf dem beide Websites nebeneinander mit und ohne Layoutoptimierung geladen werden
WebPageTest-Filmstreifen, der das Laden der beiden Websites nebeneinander mit und ohne Layoutoptimierungen zeigt
[
  {
    "name": "",
    "entryType": "layout-shift",
    "startTime": 3070.9349999997357,
    "duration": 0,
    "value": 0.000050272187989256116,
    "hadRecentInput": false,
    "lastInputTime": 0
  }
]

Laut dem benutzerdefinierten Messwert kommt es immer noch nach 3.071 Millisekunden (ungefähr zur selben Zeit wie zuvor) zu einer Layoutverschiebung. Die Schwere der Verschiebung ist jedoch deutlich geringer: 0,005 %. Damit kann ich leben.

Aus dem Filmstreifen geht auch hervor, dass die <h1>-Schrift sofort auf eine Systemschrift umgestellt wird, damit Nutzer sie schneller lesen können.

Fazit

Komplexe Websites werden wahrscheinlich wesentlich mehr Layoutverschiebungen als in diesem Beispiel feststellen, aber der Abhilfeprozess ist immer noch der gleiche: Fügen Sie WebPageTest Messwerte zur Layoutinstabilität hinzu, vergleichen Sie die Ergebnisse mit dem visuellen Lade-Filmstreifen, um die Fehler zu identifizieren, und implementieren Sie eine Korrektur mithilfe von Platzhaltern, um den Bildschirmplatz zu reservieren.

(Noch etwas) Layoutinstabilität von echten Nutzern messen

Es ist schön, WebPageTest vor und nach einer Optimierung auf einer Seite ausführen und eine Verbesserung eines Messwerts sehen zu können. Was aber wirklich zählt, ist, dass die Nutzerfreundlichkeit tatsächlich besser wird. Ist das nicht der Grund, warum wir die Website verbessern möchten?

Es wäre also toll, wenn wir die Layoutinstabilität von echten Nutzern zusammen mit unseren traditionellen Web-Leistungsmesswerten messen würden. Dies ist ein wichtiger Bestandteil der Optimierungs-Feedbackschleife, da wir anhand der Daten aus dem Feld erkennen können, wo die Probleme liegen und ob unsere Fehlerkorrekturen einen positiven Unterschied gemacht haben.

Sie können nicht nur eigene Daten zur Layoutinstabilität erheben, sondern auch den Chrome UX Report nutzen. Dieser enthält Daten zur kumulativen Layoutverschiebung von echten Nutzern auf Millionen von Websites. So können Sie herausfinden, wie Sie (oder Ihre Mitbewerber) abschneiden, oder sich die Layoutstabilität im Web ansehen.