Interaktion für den nächsten Farbauftrag optimieren

Hier erfahren Sie, wie Sie den Messwert „Interaction to Next Paint“ für Ihre Website optimieren.

Interaction to Next Paint (INP) ist ein stabiler Core Web Vital-Messwert, mit dem die Reaktionszeit einer Seite auf Nutzerinteraktionen insgesamt bewertet wird. Dazu wird die Latenz aller qualifizierenden Interaktionen erfasst, die während des Besuchs eines Nutzers auf einer Seite stattfinden. Der endgültige INP-Wert ist die längste beobachtete Interaktion, wobei manchmal Ausreißer ignoriert werden.

Für eine gute Nutzerfreundlichkeit sollten Websites einen „Interaction to Next Paint“-Wert von 200 Millisekunden oder weniger anstreben. Damit Sie dieses Ziel für die meisten Ihrer Nutzer erreichen, ist der 75. Perzentilwert der Seitenladezeiten ein guter Messwert. Dieser sollte für Mobilgeräte und Computer getrennt gemessen werden.

Gute INP-Werte liegen bei 200 Millisekunden oder weniger, schlechte Werte bei mehr als 500 Millisekunden. Werte dazwischen müssen optimiert werden.

Je nach Website gibt es möglicherweise nur wenige oder gar keine Interaktionen, z. B. Seiten mit hauptsächlich Text und Bildern, die nur wenige oder gar keine interaktiven Elemente enthalten. Bei Websites wie Texteditoren oder Spielen kann es Hunderte oder sogar Tausende von Interaktionen geben. In beiden Fällen, bei denen der INP hoch ist, ist die Nutzerfreundlichkeit gefährdet.

Die Verbesserung der Nutzerfreundlichkeit erfordert Zeit und Mühe, aber das Ergebnis ist eine bessere Nutzererfahrung. In diesem Leitfaden wird ein Weg zur Verbesserung der INP beschrieben.

Herausfinden, was zu einer schlechten INP führt

Bevor Sie langsame Interaktionen beheben können, benötigen Sie Daten, anhand derer Sie feststellen können, ob die INP Ihrer Website schlecht ist oder verbessert werden muss. Sobald Sie diese Informationen haben, können Sie mit der Diagnose langsamer Interaktionen beginnen und sich auf die Suche nach einer Lösung machen.

Langsame Interaktionen im Feld finden

Idealerweise beginnen Sie mit der Optimierung von INP mit Felddaten. Idealerweise liefern Felddaten von einem RUM-Anbieter (Real User Monitoring) nicht nur den INP-Wert einer Seite, sondern auch Kontextdaten, die Aufschluss darüber geben, welche Interaktion für den INP-Wert selbst verantwortlich war, ob die Interaktion während oder nach dem Seitenaufbau stattgefunden hat, die Art der Interaktion (Klick, Tastenanschlag oder Tippen) und andere wertvolle Informationen.

Wenn Sie keine RUM-Daten verwenden, wird im Leitfaden zu INP-Felddaten empfohlen, den Bericht zur Nutzererfahrung in Chrome (Chrome User Experience, CrUX) über PageSpeed Insights zu verwenden, um Lücken zu schließen. CrUX ist der offizielle Datensatz des Core Web Vitals-Programms und bietet eine allgemeine Zusammenfassung der Messwerte für Millionen von Websites, einschließlich INP. CrUX bietet jedoch häufig nicht die Kontextdaten, die Sie von einem RUM-Anbieter erhalten würden, um Probleme zu analysieren. Aus diesem Grund empfehlen wir weiterhin, nach Möglichkeit einen RUM-Anbieter zu verwenden oder eine eigene RUM-Lösung zu implementieren, um die in CrUX verfügbaren Daten zu ergänzen.

Langsame Interaktionen im Lab diagnostizieren

Idealerweise sollten Sie mit den Tests im Lab beginnen, sobald Sie Felddaten haben, die auf langsame Interaktionen hinweisen. In Ermangelung von Felddaten gibt es einige Strategien, um langsame Interaktionen im Lab zu identifizieren. Zu diesen Strategien gehören das Nachvollziehen gängiger Nutzerflüsse und das Testen von Interaktionen, sowie das Interagieren mit der Seite während des Ladevorgangs, wenn der Hauptthread oft am stärksten ausgelastet ist, um langsame Interaktionen während dieses wichtigen Teils der Nutzererfahrung aufzudecken.

Interaktionen optimieren

Sobald Sie eine langsame Interaktion identifiziert und sie manuell im Lab reproduzieren können, besteht der nächste Schritt darin, sie zu optimieren. Interaktionen lassen sich in drei Phasen unterteilen:

  1. Die Eingabeverzögerung, die beginnt, wenn der Nutzer eine Interaktion mit der Seite beginnt, und endet, wenn die Ereignis-Callbacks für die Interaktion ausgeführt werden.
  2. Die Verarbeitungsdauer, die aus der Zeit besteht, die zum Ausführen der Ereignis-Callbacks benötigt wird.
  3. Die Darstellungsverzögerung, also die Zeit, die der Browser benötigt, um den nächsten Frame mit dem visuellen Ergebnis der Interaktion anzuzeigen.

Die Summe dieser drei Phasen ist die Gesamtlatenz der Interaktion. Jede Phase einer Interaktion trägt zu einer gewissen Zeit zur Gesamtlatenz der Interaktion bei. Daher ist es wichtig zu wissen, wie Sie jeden Teil der Interaktion so optimieren können, dass er so kurz wie möglich ausgeführt wird.

Eingabeverzögerung ermitteln und reduzieren

Wenn ein Nutzer mit einer Seite interagiert, ist der erste Teil dieser Interaktion die Eingabeverzögerung. Je nach anderen Aktivitäten auf der Seite können die Eingabeverzögerungen erheblich sein. Das kann an Aktivitäten im Hauptthread liegen (z. B. beim Laden, Parsen und Kompilieren von Scripts), an der Abrufverarbeitung, an Timerfunktionen oder sogar an anderen Interaktionen, die in schneller Folge erfolgen und sich überschneiden.

Unabhängig von der Ursache der Eingabeverzögerung einer Interaktion sollten Sie diese auf ein Minimum reduzieren, damit Interaktionen so schnell wie möglich Ereignis-Callbacks ausführen können.

Beziehung zwischen Scriptauswertung und langen Aufgaben beim Start

Ein wichtiger Aspekt der Interaktivität im Seitenlebenszyklus ist der Start. Beim Laden einer Seite wird sie zuerst gerendert. Beachten Sie jedoch, dass das Rendern nicht bedeutet, dass die Seite vollständig geladen ist. Je nachdem, wie viele Ressourcen eine Seite benötigt, um vollständig funktionsfähig zu sein, versuchen Nutzer möglicherweise, mit der Seite zu interagieren, während sie noch geladen wird.

Die Scriptauswertung kann die Eingabeverzögerung einer Interaktion während des Ladens einer Seite verlängern. Nachdem eine JavaScript-Datei aus dem Netzwerk abgerufen wurde, muss der Browser noch einige Aufgaben ausführen, bevor das JavaScript ausgeführt werden kann. Dazu gehört das Parsen eines Scripts, um sicherzustellen, dass die Syntax gültig ist, das Kompilieren in Bytecode und schließlich die Ausführung.

Je nach Größe eines Scripts können dadurch lange Aufgaben im Haupt-Thread entstehen, was die Reaktion des Browsers auf andere Nutzerinteraktionen verzögert. Damit Ihre Seite während des Seitenaufbaus auf Nutzereingaben reagieren kann, ist es wichtig zu wissen, wie Sie die Wahrscheinlichkeit langer Aufgaben während des Seitenaufbaus verringern können, damit die Seite reaktionsschnell bleibt.

Ereignis-Callbacks optimieren

Die Eingabeverzögerung ist nur der erste Teil der INP-Messung. Außerdem müssen Sie dafür sorgen, dass die Ereignis-Callbacks, die als Reaktion auf eine Nutzerinteraktion ausgeführt werden, so schnell wie möglich abgeschlossen werden können.

Oft dem Hauptfaden weichen

Der beste allgemeine Rat zur Optimierung von Ereignis-Callbacks ist, in ihnen so wenig Arbeit wie möglich zu erledigen. Ihre Interaktionslogik kann jedoch komplex sein und Sie können die Arbeit der Nutzer nur geringfügig reduzieren.

Wenn das bei Ihrer Website der Fall ist, können Sie versuchen, die Arbeit in Ereignis-Callbacks in separate Aufgaben aufzuteilen. So wird verhindert, dass die gemeinsame Arbeit zu einer langen Aufgabe wird, die den Hauptthread blockiert. Dadurch können andere Interaktionen, die andernfalls auf den Hauptthread warten müssten, früher ausgeführt werden.

setTimeout ist eine Möglichkeit, Aufgaben aufzuteilen, da der übergebene Rückruf in einer neuen Aufgabe ausgeführt wird. Sie können setTimeout allein verwenden oder seine Verwendung in einer separaten Funktion abstrahieren, um die Ausgabe ergonomischer zu gestalten.

Undifferenziertes Übergeben ist besser als gar kein Übergeben. Es gibt jedoch eine differenziertere Möglichkeit, den Hauptthread zu übergeben. Dabei wird nur unmittelbar nach einem Ereignis-Callback übergeben, der die Benutzeroberfläche aktualisiert, damit die Renderinglogik früher ausgeführt werden kann.

Yield aktivieren, damit das Rendern früher beginnt

Eine fortgeschrittenere Methode zum Ausgeben besteht darin, den Code in Ihren Ereignis-Callbacks so zu strukturieren, dass nur die Logik ausgeführt wird, die für die Anwendung visueller Updates für den nächsten Frame erforderlich ist. Alles andere kann auf eine nachfolgende Aufgabe verschoben werden. Dadurch bleiben Callbacks nicht nur effizient und wendig, sondern die Renderingzeit für Interaktionen wird auch verbessert, da visuelle Aktualisierungen nicht durch Ereignis-Callback-Code blockiert werden.

Stellen Sie sich beispielsweise einen Rich-Text-Editor vor, der Text beim Tippen formatiert, aber auch andere Aspekte der Benutzeroberfläche als Reaktion auf das Geschriebene aktualisiert (z. B. Wortanzahl, Hervorhebung von Rechtschreibfehlern und anderes wichtiges visuelles Feedback). Außerdem muss die Anwendung möglicherweise das Geschriebene speichern, damit Sie bei einem Wechsel zu einer anderen Seite und der Rückkehr nicht Ihre Arbeit verlieren.

In diesem Beispiel müssen die folgenden vier Dinge als Reaktion auf vom Nutzer eingegebene Zeichen passieren. Allerdings muss nur der erste Punkt erledigt sein, bevor der nächste Frame angezeigt wird.

  1. Aktualisieren Sie das Textfeld mit dem Text, den der Nutzer eingegeben hat, und wenden Sie die erforderliche Formatierung an.
  2. Aktualisieren Sie den Teil der Benutzeroberfläche, in dem die aktuelle Wortanzahl angezeigt wird.
  3. Logik ausführen, um auf Rechtschreibfehler zu prüfen
  4. Speichern Sie die letzten Änderungen (entweder lokal oder in einer Remote-Datenbank).

Der Code dazu könnte in etwa so aussehen:

textBox.addEventListener('input', (inputEvent) => {
 
// Update the UI immediately, so the changes the user made
 
// are visible as soon as the next frame is presented.
  updateTextBox
(inputEvent);

 
// Use `setTimeout` to defer all other work until at least the next
 
// frame by queuing a task in a `requestAnimationFrame()` callback.
  requestAnimationFrame
(() => {
    setTimeout
(() => {
     
const text = textBox.textContent;
      updateWordCount
(text);
      checkSpelling
(text);
      saveChanges
(text);
   
}, 0);
 
});
});

Die folgende Visualisierung zeigt, wie sich die Verarbeitungsdauer und damit die Gesamtlatenz der Interaktion durch das Verschieben nicht kritischer Updates auf den nächsten Frame verkürzen lässt.

Eine Darstellung einer Tastaturinteraktion und nachfolgender Aufgaben in zwei Szenarien. In der oberen Abbildung werden die renderkritische Aufgabe und alle nachfolgenden Hintergrundaufgaben synchron ausgeführt, bis die Möglichkeit besteht, einen Frame zu präsentieren. In der unteren Abbildung wird die renderkritische Arbeit zuerst ausgeführt und dann dem Hauptthread übergeben, um einen neuen Frame schneller zu präsentieren. Danach werden die Hintergrundaufgaben ausgeführt.
Klicken Sie auf die Abbildung oben, um eine hochauflösende Version aufzurufen.

Die Verwendung von setTimeout() in einem requestAnimationFrame()-Aufruf im vorherigen Codebeispiel ist zwar etwas esoterisch, aber eine effektive Methode, die in allen Browsern funktioniert, um sicherzustellen, dass der nicht kritische Code den nächsten Frame nicht blockiert.

Layout-Flattern vermeiden

Layout-Trashing, manchmal auch als erzwungenes synchrones Layout bezeichnet, ist ein Problem mit der Renderingleistung, bei dem das Layout synchron erfolgt. Das passiert, wenn Sie Stile in JavaScript aktualisieren und dann in derselben Aufgabe lesen. Es gibt viele Eigenschaften in JavaScript, die zu Layout-Überlastungen führen können.

Eine Visualisierung von Layout-Überlastung, wie sie im Bereich „Leistung“ der Chrome-Entwicklertools angezeigt wird.
Beispiel für Layout-Trashing, wie im Bereich „Leistung“ der Chrome DevTools zu sehen. Rendering-Aufgaben, die ein Layout-Trashing beinhalten, werden mit einem roten Dreieck in der oberen rechten Ecke des Teils des Aufrufstacks gekennzeichnet, oft mit der Beschriftung Stil neu berechnen oder Layout.

Layout-Trashing ist ein Leistungsengpass, da der Browser durch das Aktualisieren von Stilen und das sofortige Anfordern der Werte dieser Stile in JavaScript gezwungen ist, synchrone Layoutarbeiten auszuführen, die er sonst asynchron ausführen könnte, nachdem die Ereignis-Callbacks beendet sind.

Verzögerung bei der Präsentation minimieren

Die Darstellungsverzögerung einer Interaktion beginnt, wenn die Ereignis-Callbacks einer Interaktion beendet sind, und endet, wenn der Browser den nächsten Frame mit den sich daraus ergebenden visuellen Änderungen zeichnen kann.

DOM-Größe minimieren

Wenn das DOM einer Seite klein ist, ist das Rendering in der Regel schnell abgeschlossen. Wenn DOMs jedoch sehr groß werden, steigt der Aufwand für das Rendern mit zunehmender DOM-Größe. Das Verhältnis zwischen dem Aufwand für das Rendern und der Größe des DOM ist nicht linear, aber das Rendern großer DOMs erfordert mehr Aufwand als das Rendern kleiner DOMs. Ein großes DOM ist in zwei Fällen problematisch:

  1. Beim ersten Rendern der Seite, wenn ein großes DOM viel Arbeit erfordert, um den ursprünglichen Zustand der Seite zu rendern.
  2. Als Reaktion auf eine Nutzerinteraktion, bei der ein großes DOM zu sehr aufwendigen Rendering-Aktualisierungen führen kann und daher die Zeit verlängert, die der Browser für die Darstellung des nächsten Frames benötigt.

Es gibt Fälle, in denen große DOMs nicht wesentlich reduziert werden können. Es gibt zwar Möglichkeiten, die DOM-Größe zu reduzieren, z. B. durch Ebenenreduktion oder das Hinzufügen von Elementen zum DOM während Nutzerinteraktionen, um die anfängliche DOM-Größe klein zu halten, aber diese Techniken sind möglicherweise nicht ausreichend.

content-visibility zum Lazy-Rendering von Elementen außerhalb des sichtbaren Bereichs verwenden

Mit der CSS-Eigenschaft content-visibility können Sie sowohl die Menge an Rendering-Arbeit beim Seitenaufbau als auch die Menge an Rendering-Arbeit in Reaktion auf Nutzerinteraktionen begrenzen. Das entspricht dem Lazy-Rendering von Elementen, wenn sie sich dem Darstellungsbereich nähern. Es kann etwas dauern, bis Sie content-visibility effektiv einsetzen können. Es lohnt sich aber, zu prüfen, ob sich dadurch die Renderingzeit verkürzt und die INP Ihrer Seite verbessert.

Leistungskosten beim Rendern von HTML mit JavaScript

Wo HTML ist, ist auch HTML-Parsing. Nachdem der Browser das HTML in ein DOM geparst hat, muss er Stile darauf anwenden, Layoutberechnungen ausführen und das Layout anschließend rendern. Das ist unvermeidlich, aber wie Sie HTML rendern, ist wichtig.

Wenn der Server HTML sendet, wird es im Browser als Stream empfangen. Beim Streaming wird die HTML-Antwort vom Server in mehreren Teilen empfangen. Der Browser optimiert die Verarbeitung eines Streams, indem er die einzelnen Chunks des Streams nach und nach analysiert und bitweise rendert. Dies ist eine Leistungsoptimierung, da der Browser beim Seitenaufbau automatisch und regelmäßig in den Ruhemodus wechselt.

Beim ersten Besuch einer Website ist immer ein wenig HTML erforderlich. Ein gängiger Ansatz besteht darin, mit einem minimalen Anfangs-HTML-Code zu beginnen und dann JavaScript zu verwenden, um den Inhaltsbereich zu füllen. Auch spätere Aktualisierungen dieses Inhaltsbereichs erfolgen aufgrund von Nutzerinteraktionen. Dies wird in der Regel als SPA-Modell (Single-Page-Anwendung) bezeichnet. Ein Nachteil dieses Musters ist, dass beim Rendern von HTML mit JavaScript auf dem Client nicht nur die Kosten für die JavaScript-Verarbeitung zum Erstellen dieser HTML-Datei anfallen, sondern auch, dass der Browser nicht reagiert, bis das Parsen und Rendern der HTML-Datei abgeschlossen ist.

Denken Sie jedoch daran, dass selbst Websites, die keine SPAs sind, wahrscheinlich aufgrund von Interaktionen ein gewisses Maß an HTML-Rendering über JavaScript erfordern. Das ist in der Regel in Ordnung, solange Sie nicht große Mengen an HTML auf dem Client rendern, was die Darstellung des nächsten Frames verzögern kann. Es ist jedoch wichtig, die Leistungsauswirkungen dieses Ansatzes für das Rendern von HTML im Browser zu verstehen und zu wissen, wie sich das auf die Reaktionsfähigkeit Ihrer Website auf Nutzereingaben auswirken kann, wenn Sie viel HTML über JavaScript rendern.

Fazit

Die Verbesserung des INP Ihrer Website ist ein iterativer Prozess. Wenn Sie eine langsame Interaktion im Feld beheben, werden Sie wahrscheinlich – insbesondere, wenn Ihre Website viele interaktive Elemente enthält – weitere langsame Interaktionen finden, die Sie ebenfalls optimieren müssen.

Der Schlüssel zur Verbesserung der INP ist Ausdauer. Mit der Zeit können Sie die Responsivität Ihrer Seite so anpassen, dass Nutzer mit der von Ihnen bereitgestellten Umgebung zufrieden sind. Es ist auch wahrscheinlich, dass Sie bei der Entwicklung neuer Funktionen für Ihre Nutzer möglicherweise denselben Prozess durchlaufen müssen, um die Interaktionen für diese Nutzer zu optimieren. Das erfordert Zeit und Mühe, aber es lohnt sich.

Hero-Image von Unsplash, von David Pisnoy, gemäß der Unsplash-Lizenz geändert.