Vermeiden Sie große, komplexe Layouts und Layoutüberlastungen

Beim Layout erkennt der Browser die geometrischen Informationen für Elemente, d. h. ihre Größe und ihre Position auf der Seite. Jedes Element enthält explizite oder implizite Größeninformationen basierend auf dem verwendeten CSS-Code, dem Inhalt des Elements oder einem übergeordneten Element. Dieser Vorgang wird in Chrome als Layout bezeichnet.

Beim Layout ermittelt der Browser die geometrischen Informationen der Elemente: ihre Größe und ihre Position auf der Seite. Jedes Element enthält explizite oder implizite Größeninformationen basierend auf dem verwendeten CSS-Code, dem Inhalt des Elements oder einem übergeordneten Element. Dieser Prozess wird in Chrome (und abgeleiteten Browsern wie Edge) und Safari als Layout bezeichnet. In Firefox heißt das Reflow, der Prozess ist jedoch derselbe.

Ähnlich wie bei Stilberechnungen haben Layoutkosten folgende unmittelbare Bedenken:

  1. Die Anzahl der Elemente, die ein Layout erfordern. Dies ist ein Nebenprodukt der DOM-Größe der Seite.
  2. Die Komplexität dieser Layouts.

Zusammenfassung

  • Das Layout hat einen direkten Effekt auf die Interaktionslatenz.
  • Das Layout bezieht sich normalerweise auf das gesamte Dokument.
  • Die Anzahl der DOM-Elemente wirkt sich auf die Leistung aus. Sie sollten das Layout möglichst vermeiden.
  • Vermeiden Sie erzwungene synchrone Layouts und Layoutüberlastungen. Lesen Sie Stilwerte und nehmen Sie dann Stiländerungen vor.

Die Auswirkungen des Layouts auf die Interaktionslatenz

Wenn ein Nutzer mit der Seite interagiert, sollten diese Interaktionen so schnell wie möglich erfolgen. Die Zeit, die eine Interaktion benötigt, also bis zu dem Zeitpunkt, an dem der Browser den nächsten Frame für die Anzeige der Ergebnisse der Interaktion präsentiert, wird als Interaktionslatenz bezeichnet. Dies ist ein Aspekt der Seitenleistung, der mit dem Messwert Interaction to Next Paint erfasst wird.

Die Zeit, die der Browser benötigt, um den nächsten Frame als Reaktion auf eine Nutzerinteraktion zu präsentieren, wird als Darstellungsverzögerung der Interaktion bezeichnet. Das Ziel einer Interaktion ist es, visuelles Feedback zu geben, um den Nutzenden zu signalisieren, dass etwas passiert ist. Visuelle Aktualisierungen können einiges an Layout-Arbeit erfordern, um dieses Ziel zu erreichen.

Um den INP für Ihre Website so niedrig wie möglich zu halten, ist es wichtig, das Layout nach Möglichkeit zu vermeiden. Wenn das Layout nicht vollständig vermieden werden kann, ist es wichtig, diese Layoutarbeit einzuschränken, damit der Browser den nächsten Frame schnell anzeigen kann.

Layout möglichst vermeiden

Wenn Sie Stile ändern, prüft der Browser, ob für eine der Änderungen das Layout berechnet und die Rendering-Baumstruktur aktualisiert werden muss. Für Änderungen an „geometrischen Eigenschaften“ wie Breite, Höhe, links oder oben ist ein Layout erforderlich.

.box {
  width: 20px;
  height: 20px;
}

/**
  * Changing width and height
  * triggers layout.
  */

.box--expanded {
  width: 200px;
  height: 350px;
}

Das Layout bezieht sich fast immer auf das gesamte Dokument. Wenn Sie viele Elemente haben, wird es sehr lange dauern, die Positionen und Dimensionen herauszufinden.

Wenn sich das Layout nicht vermeiden lässt, ist es wichtig, dass Sie wieder die Chrome-Entwicklertools verwenden, um die Dauer der Ausführung zu ermitteln und festzustellen, ob das Layout die Ursache eines Engpasses ist. Öffnen Sie zuerst die Entwicklertools, gehen Sie zum Tab „Zeitachse“, klicken Sie auf „Aufnehmen“ und interagieren Sie mit Ihrer Website. Wenn Sie die Aufzeichnung beenden, sehen Sie eine Aufschlüsselung der Leistung Ihrer Website:

Entwicklertools, die eine lange Zeit im Layout anzeigen.

Bei der Untersuchung des Trace im obigen Beispiel sehen wir, dass für jeden Frame mehr als 28 Millisekunden im Layout aufgewendet werden, was jedoch viel zu hoch ist, wenn wir 16 Millisekunden haben, um einen Frame auf dem Bildschirm in einer Animation anzuzeigen. Sie können auch sehen,dass die Entwicklertools die Baumgröße (in diesem Fall 1.618 Elemente) und die Anzahl der Knoten (in diesem Fall 5) angeben, für die das Layout erforderlich war.

Generell gilt, ein Layout nach Möglichkeit zu vermeiden. Es ist jedoch nicht immer möglich, ein solches Layout zu vermeiden. Wenn sich das Layout nicht vermeiden lässt, sollten Sie wissen, dass die Kosten des Layouts mit der Größe des DOMs zusammenhängen. Obwohl die Beziehung zwischen den beiden nicht eng miteinander verbunden ist, verursachen größere DOMs im Allgemeinen höhere Layoutkosten.

Erzwungene synchrone Layouts vermeiden

Beim Versand eines Frames an einen Bildschirm gilt diese Reihenfolge:

Flexbox als Layout verwenden.

Zuerst wird das JavaScript ausgeführt, dann die Stilberechnungen und dann das Layout. Es ist jedoch möglich, einen Browser dazu zu zwingen, das Layout früher mit JavaScript auszuführen. Dies wird als erzwungenes synchrones Layout bezeichnet.

Zunächst ist zu beachten, dass während der Ausführung von JavaScript alle alten Layoutwerte aus dem vorherigen Frame bekannt sind und für Sie zur Abfrage verfügbar sind. Wenn Sie also beispielsweise die Höhe eines Elements am Anfang des Frames (wir nennen es „box“) ausschreiben möchten, können Sie Code wie den folgenden schreiben:

// Schedule our function to run at the start of the frame:
requestAnimationFrame(logBoxHeight);

function logBoxHeight () {
  // Gets the height of the box in pixels and logs it out:
  console.log(box.offsetHeight);
}

Wenn Sie den Stil der Box geändert haben, bevor Sie nach ihrer Höhe fragen, kann es zu Problemen kommen:

function logBoxHeight () {
  box.classList.add('super-big');

  // Gets the height of the box in pixels and logs it out:
  console.log(box.offsetHeight);
}

Um nun die Frage zur Höhe zu beantworten, muss der Browser zuerst die Stiländerung anwenden, da die Klasse super-big hinzugefügt wurde, und dann das Layout ausführen. Erst dann kann die richtige Höhe zurückgegeben werden. Das ist unnötiger und potenziell teurer Aufwand.

Aus diesem Grund sollten Sie immer eine Batch-Abfrage für Ihren Stil durchführen und sie zuerst ausführen, wobei der Browser die Layout-Werte des vorherigen Frames verwenden kann, und dann die Schreibvorgänge ausführen:

Bei richtiger Anwendung würde die Funktion oben wie folgt aussehen:

function logBoxHeight () {
  // Gets the height of the box in pixels and logs it out:
  console.log(box.offsetHeight);

  box.classList.add('super-big');
}

In den meisten Fällen müssen Sie keine Stile anwenden und anschließend Werte abfragen. Die Verwendung der Werte des letzten Frames sollte ausreichen. Wenn Sie die Stilberechnungen und das Layout synchron und früher ausführen, als es der Browser gerne hätte, entstehen potenzielle Engpässe, die Sie normalerweise nicht tun sollten.

Seitenübergreifendes Layout vermeiden

Es gibt eine Möglichkeit, erzwungene synchrone Layouts noch weiter zu verschlimmern, indem Sie viele davon schnell hintereinander erstellen. Sehen Sie sich diesen Code an:

function resizeAllParagraphsToMatchBlockWidth () {
  // Puts the browser into a read-write-read-write cycle.
  for (let i = 0; i < paragraphs.length; i++) {
    paragraphs[i].style.width = `${box.offsetWidth}px`;
  }
}

Dieser Code führt eine Schleife über eine Gruppe von Absätzen und legt die Breite jedes Absatzes so fest, dass sie der Breite des Elements "box" entspricht. Es sieht harmlos aus, aber das Problem ist, dass bei jeder Iteration der Schleife ein Stilwert (box.offsetWidth) gelesen und dann sofort die Breite eines Absatzes (paragraphs[i].style.width) aktualisiert wird. Bei der nächsten Iteration der Schleife muss der Browser berücksichtigen, dass sich die Stile seit der letzten Abfrage von offsetWidth (in der vorherigen Iteration) geändert haben. Daher müssen die Stiländerungen angewendet und das Layout ausgeführt werden. Das passiert bei jedem Durchlauf.

Die Korrektur für dieses Beispiel besteht darin, Werte noch einmal zu lesen und dann zu schreiben:

// Read.
const width = box.offsetWidth;

function resizeAllParagraphsToMatchBlockWidth () {
  for (let i = 0; i < paragraphs.length; i++) {
    // Now write.
    paragraphs[i].style.width = `${width}px`;
  }
}

Um die Sicherheit zu gewährleisten, sollten Sie FastDOM verwenden. Damit werden Ihre Lese- und Schreibvorgänge automatisch für Sie in Batches zusammengefasst und Sie sollten verhindern, dass Sie versehentlich erzwungene synchrone Layouts oder Layout-Überlastungen auslösen.

Hero-Image aus Unsplash von Hal Gatewood