Das Layout ist der Ort, an dem der Browser die geometrischen Informationen für Elemente ermittelt, d. h. ihre Größe und Position auf der Seite. Jedes Element enthält explizite oder implizite Größeninformationen basierend auf dem verwendeten CSS, 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 Position auf der Seite. Jedes Element enthält explizite oder implizite Größeninformationen basierend auf dem verwendeten CSS, dem Inhalt des Elements oder einem übergeordneten Element. Dieser Vorgang wird in Chrome (und abgeleiteten Browsern wie Edge) und Safari als Layout bezeichnet. In Firefox heißt das Reflow, aber die Vorgehensweise ist im Grunde derselbe.
Ähnlich wie bei Stilberechnungen sind die unmittelbaren Bedenken bezüglich der Layoutkosten folgende:
- Die Anzahl der Elemente, die ein Layout erfordern. Dies ist ein Nebenprodukt der DOM-Größe der Seite.
- Die Komplexität dieser Layouts.
Zusammenfassung
- Das Layout hat direkte Auswirkungen 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 nicht auslösen.
- Vermeiden Sie erzwungene synchrone Layouts und Layout-Drashing. Lesen Sie Stilwerte und nehmen Sie dann Stiländerungen vor.
Die Auswirkungen des Layouts auf die Interaktionslatenz
Interaktionen eines Nutzers mit der Seite sollten so schnell wie möglich erfolgen. Die Zeit, die für den Abschluss einer Interaktion benötigt wird – die endet, wenn der Browser den nächsten Frame anzeigt, um das Ergebnis der Interaktion anzuzeigen – wird als Interaktionslatenz bezeichnet. Dies ist ein Aspekt der Seitenleistung, der mit dem Messwert Interaction to Next Paint gemessen wird.
Die Zeit, die der Browser benötigt, um auf eine Nutzerinteraktion hin den nächsten Frame anzuzeigen, wird als Darstellungsverzögerung der Interaktion bezeichnet. Das Ziel einer Interaktion besteht darin, visuelles Feedback zu geben, um der Nutzenden zu signalisieren, dass etwas passiert ist. Visuelle Aktualisierungen können ein gewisses Maß an Layoutarbeit erfordern, um dieses Ziel zu erreichen.
Um den INP-Wert Ihrer Website so niedrig wie möglich zu halten, ist es wichtig, nach Möglichkeit auf Layout zu verzichten. Wenn es nicht möglich ist, das Layout vollständig zu vermeiden, ist es wichtig, die Layoutarbeit einzuschränken, damit der Browser den nächsten Frame schnell anzeigen kann.
Vermeiden Sie nach Möglichkeit ein Layout.
Wenn Sie Stile ändern, prüft der Browser, ob für die Änderungen eine Berechnung des Layouts erforderlich ist und ob die Rendering-Struktur aktualisiert werden muss. Änderungen an „geometrischen Eigenschaften“, wie Breite, Höhe, links oder oben, erfordern ein Layout.
.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 viel Zeit in Anspruch nehmen, die Positionen und Abmessungen aller Elemente zu ermitteln.
Wenn es nicht möglich ist, auf ein Layout zu verzichten, sollten Sie erneut die Chrome-Entwicklertools verwenden, um zu sehen, wie lange es noch dauert, und zu ermitteln, ob das Layout die Ursache für einen Engpass ist. Öffnen Sie zuerst die Entwicklertools, rufen Sie den Tab „Zeitachse“ auf, 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 mit einer langen Zeit im Layout](https://web.dev/static/articles/avoid-large-complex-layouts-and-layout-thrashing/image/devtools-showing-long-i-9f35099ab9d22.png?authuser=6&hl=de)
Wenn wir uns den Trace im obigen Beispiel genauer ansehen, stellen wir fest, dass für jeden Frame mehr als 28 Millisekunden innerhalb des Layouts aufgewendet werden. Wenn wir 16 Millisekunden Zeit haben, um einen Frame auf dem Bildschirm in einer Animation zu erhalten, ist das viel zu hoch. Sie können auch sehen, dass die Entwicklertools Ihnen die Baumgröße (in diesem Fall 1.618 Elemente) und die Anzahl der Knoten, für die ein Layout erforderlich war (5 in diesem Fall), mitteilen.
Grundsätzlich wird hier jedoch empfohlen, das Layout nach Möglichkeit zu vermeiden. Es ist aber nicht immer möglich, auf ein Layout zu verzichten. Wenn Sie das Layout nicht vermeiden können, wissen Sie, dass die Kosten des Layouts in Beziehung zur Größe des DOMs stehen. Obwohl die Beziehung zwischen den beiden nicht eng gekoppelt ist, verursachen größere DOMs in der Regel höhere Layoutkosten.
Erzwungene synchrone Layouts vermeiden
Beim Versand eines Frames to Screen wird diese Reihenfolge festgelegt:
![Flexbox als Layout verwenden](https://web.dev/static/articles/avoid-large-complex-layouts-and-layout-thrashing/image/using-flexbox-layout-0c9955c54a296.jpg?authuser=6&hl=de)
Zuerst wird der JavaScript-Code ausgeführt, dann Stilberechnungen und dann 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.
Da der JavaScript-Code ausgeführt wird, sind als Erstes alle alten Layoutwerte aus dem vorherigen Frame bekannt und können abgefragt werden. Wenn Sie also zum Beispiel die Höhe eines Elements (wir nennen es „Box“) am Anfang des Frames schreiben 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);
}
Es kann zu Problemen kommen, wenn Sie den Stil der Box geändert haben, bevor Sie nach ihrer Höhe fragen:
function logBoxHeight () {
box.classList.add('super-big');
// Gets the height of the box in pixels and logs it out:
console.log(box.offsetHeight);
}
Um die Frage nach der Höhe beantworten zu können, muss der Browser zuerst die Stiländerung anwenden (durch Hinzufügen der Klasse super-big
) und dann das Layout ausführen. Nur dann kann die richtige Höhe zurückgegeben werden. Das ist unnötig und potenziell kostspielig.
Aus diesem Grund sollten Sie Ihre Stillesevorgänge immer zuerst in Batches ausführen (wo der Browser die Layoutwerte des vorherigen Frames verwenden kann) und dann die Schreibvorgänge ausführen:
Bei korrekter Anwendung würde die obige Funktion 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 dann Werte abfragen. Die Verwendung der Werte des letzten Frames sollte ausreichen. Werden Stilberechnungen und das Layout synchron und früher ausgeführt, als es der Browser eigentlich möchte, können Engpässe auftreten.
Layout-Thrashing vermeiden
Es gibt eine Möglichkeit, erzwungene synchrone Layouts noch zu verschlimmern: Verwenden Sie viele schnell hintereinander. 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 durch und legt die Breite jedes Absatzes so fest, dass sie der Breite eines Elements namens „box“ entspricht. Sie 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 die Stile seit der letzten Anforderung von offsetWidth
(in der vorherigen Iteration) geändert wurden. Daher muss er die Stiländerungen anwenden und das Layout ausführen. Dies geschieht bei jedem einzelnen Durchlauf.
Die Korrektur für dieses Beispiel besteht darin, die Werte erneut read und dann write zu lesen:
// Read.
const width = box.offsetWidth;
function resizeAllParagraphsToMatchBlockWidth () {
for (let i = 0; i < paragraphs.length; i++) {
// Now write.
paragraphs[i].style.width = `${width}px`;
}
}
Wenn Sie Sicherheit gewährleisten möchten, sollten Sie FastDOM verwenden, das Ihre Lese- und Schreibvorgänge automatisch fasst und verhindert, dass Sie versehentlich erzwungene synchrone Layouts oder Layout-Flachen auslösen.
Hero-Image von Unsplash von Hal Gatewood