Unnötige Farben vermeiden

Paul Lewis

Einleitung

Das Painting der Elemente für eine Website oder Anwendung kann sehr teuer werden und sich negativ auf die Laufzeitleistung auswirken. In diesem Artikel werfen wir einen kurzen Blick darauf, was das Painting im Browser auslösen kann und wie Sie unnötige Painting-Ereignisse verhindern können.

Gemälde: Ein kurzer Rundgang

Eine der Hauptaufgaben eines Browsers ist die Konvertierung von DOM und CSS in Pixel auf dem Bildschirm. Dies geschieht in einem ziemlich komplexen Prozess. Als Erstes wird die Auszeichnung gelesen und daraus wird ein DOM-Baum erstellt. Ähnlich funktioniert es mit dem CSS und erstellt daraus das CSSOM. Das DOM und CSSOM werden dann kombiniert, und schließlich erhalten wir eine Struktur, auf der wir einige Pixel zeichnen können.

Das Malen selbst ist interessant. Diese kombinierte DOM- und CSS-Struktur wird in Chrome von Software namens Skia gerastert. Wenn Sie schon einmal mit dem canvas-Element gespielt haben, würde Ihnen die API von Skia sehr vertraut erscheinen. Es gibt viele Funktionen im moveTo- und lineTo-Stil sowie einige fortgeschrittenere Funktionen. Im Grunde werden alle Elemente, die gerendert werden müssen, in eine Sammlung von Skia-Aufrufen gebündelt, die ausgeführt werden können, und es werden eine Reihe von Bitmaps ausgegeben. Diese Bitmaps werden in die GPU hochgeladen. Diese setzt sie so zusammen, um das endgültige Bild auf dem Bildschirm zu erhalten.

Dom zu Pixel

Zu beachten ist, dass Skias Arbeitsbelastung direkt von den Stilen beeinflusst wird, die Sie auf Ihre Elemente anwenden. Wenn Sie auf Algorithmen basierende Stile verwenden, hat Skia mehr Arbeit zu tun. Colt McAnlis hat einen Artikel darüber geschrieben, wie sich CSS auf die Gewichtung des Seiten-Renderings auswirkt. Lesen Sie diesen Artikel, um weitere Informationen zu erhalten.

Vor diesem Hintergrund nimmt die Durchführung von Malerarbeiten eine gewisse Zeit in Anspruch. Wenn wir sie nicht reduzieren, wird unser Frame-Budget von ca. 16 ms überschritten. Die Nutzer werden feststellen, dass wir Frames übersehen haben, und sie als Verzögerung betrachten, was die User Experience unserer App beeinträchtigt. Das möchten wir wirklich nicht. Sehen wir uns einmal an, welche Dinge notwendig sind und was wir dagegen tun können.

Scrollen

Wenn Sie im Browser nach oben oder unten scrollen, muss der Inhalt neu gezeichnet werden, bevor er auf dem Bildschirm angezeigt wird. Das wäre nur ein kleiner Bereich, aber selbst in diesem Fall können die zu zeichnenden Elemente komplexe Stile haben. Nur weil nur eine kleine Fläche zum Anstrichen ist, heißt das nicht, dass das schnell geht.

Wenn Sie sehen möchten, welche Bereiche neu gezeichnet werden, können Sie die Funktion „Paint Rectangles anzeigen“ in den Entwicklertools von Chrome verwenden. Klicken Sie dazu einfach auf das kleine Zahnrad unten rechts. Wenn die Entwicklertools geöffnet sind, interagieren Sie einfach mit Ihrer Seite und Sie sehen blinkende Rechtecke, die anzeigen, wo und wann Chrome einen Teil Ihrer Seite gezeichnet hat.

Paint Rectangles in Chrome-Entwicklertools anzeigen
Paint-Rechtecke in den Chrome-Entwicklertools anzeigen

Die Scrollleistung ist für den Erfolg Ihrer Website entscheidend. Nutzer bemerken wirklich, wenn auf Ihrer Website oder in Ihrer App das Scrollen funktioniert und ihnen das nicht gefällt. Wir haben daher ein persönliches Interesse daran, die Farbarbeit beim Scrollen offen zu halten, damit die Nutzer Verzögerungen bei der Ausführung vermeiden.

Ich habe bereits einen Artikel zur Scrollleistung veröffentlicht. Wenn ihr mehr über die Scrollleistung erfahren möchtet, seht euch diesen mal an.

Interaktionen

Interaktionen sind eine weitere Ursache von Malerarbeiten: Schwebungen, Klicks, Berührungen, Ziehen. Immer wenn der Nutzer eine dieser Interaktionen ausführt, beispielsweise den Mauszeiger darauf bewegt, muss Chrome das betroffene Element neu zeichnen. Wenn eine große und komplexe Darstellung erforderlich ist, sinkt die Framerate ähnlich wie beim Scrollen.

Alle wünschen sich schöne, flüssige Animationen. Auch hier müssen wir prüfen, ob die Stile, die sich in unserer Animation ändern, uns zu viel Zeit kosten.

Eine bedauerliche Kombination

Eine Demo mit teuren Farben
Eine Demo mit teuren Farben

Was passiert, wenn ich scrolle und die Maus gleichzeitig bewege? Es ist durchaus möglich, dass ich versehentlich mit einem Element „interagieren“, wenn ich daran vorbeiscrolle, wodurch eine teure Farbe ausgelöst wird. Das wiederum könnte mich dazu bringen, mein Frame-Budget von ca.16,7 ms zu überschreiten (die Zeit, die wir für 60 Bilder pro Sekunde unter diesem Wert halten müssen). Ich habe eine Demo erstellt, um Ihnen genau zu zeigen, was ich meine. Hoffentlich sehen Sie beim Scrollen und Bewegen der Maus die Hover-Effekte. Aber sehen wir uns an, was die Entwicklertools von Chrome damit machen:

Die Entwicklertools von Chrome zeigen teure Frames an
Teure Frames werden in den Chrome-Entwicklertools angezeigt

Im Bild oben sehen Sie, dass die Entwicklertools die Farbgestaltung registrieren, wenn ich den Mauszeiger auf einen der Blöcke bewege. Ich habe in meiner Demo ein paar sehr schwere Stile verwendet, um meine Argumentation vorzustellen, und erreiche daher gelegentlich mein Frame-Budget. Schließlich möchte ich diese Malerarbeiten unnötig machen, und zwar vor allem dann, wenn man scrollt, wenn andere Arbeitsschritte anstehen!

Wie können wir das verhindern? Die Korrektur ist ziemlich einfach zu implementieren. Der Trick hier besteht darin, einen scroll-Handler anzuhängen, der Hover-Effekte deaktiviert und einen Timer für die erneute Aktivierung setzt. Das heißt, wir garantieren, dass wir beim Scrollen keine teuren Interaction Paints ausführen müssen. Wenn du lange genug angehalten hast, kannst du sie wieder einschalten.

Hier ist der Code:

// Used to track the enabling of hover effects
var enableTimer = 0;

/*
 * Listen for a scroll and use that to remove
 * the possibility of hover effects
 */
window.addEventListener('scroll', function() {
  clearTimeout(enableTimer);
  removeHoverClass();

  // enable after 1 second, choose your own value here!
  enableTimer = setTimeout(addHoverClass, 1000);
}, false);

/**
 * Removes the hover class from the body. Hover styles
 * are reliant on this class being present
 */
function removeHoverClass() {
  document.body.classList.remove('hover');
}

/**
 * Adds the hover class to the body. Hover styles
 * are reliant on this class being present
 */
function addHoverClass() {
  document.body.classList.add('hover');
}

Wie Sie sehen, verwenden wir eine -Klasse im Body, um zu verfolgen, ob Hover-Effekte "zulässig" sind. Die zugrunde liegenden Stile benötigen diese Klasse, um vorhanden zu sein:

/* Expect the hover class to be on the body
 before doing any hover effects */
.hover .block:hover {
 …
}

Das ist alles!

Fazit

Die Rendering-Leistung ist entscheidend für die Freude an Ihrer Anwendung. Sie sollten immer versuchen, Ihre Paint-Arbeitslast unter 16 ms zu halten. Dazu sollten Sie die Entwicklertools während des gesamten Entwicklungsprozesses einbinden, um Engpässe zu erkennen und zu beheben.

Unbeabsichtigte Interaktionen, insbesondere bei farbintensiven Elementen, können sehr kostspielig sein und beeinträchtigen die Rendering-Leistung. Wie Sie gesehen haben, können wir zur Behebung dieses Problems ein kleines Code-Snippet verwenden.

Sehen Sie sich Ihre Websites und Anwendungen an. Könnten sie etwas Schutz mit Farbe machen?