Einführung
Das Zeichnen der Elemente für eine Website oder Anwendung kann sehr teuer werden und sich negativ auf die Laufzeitleistung auswirken. In diesem Artikel sehen wir uns kurz an, was das Zeichnen im Browser auslösen kann und wie Sie unnötiges Zeichnen verhindern können.
Malen: Schneller Überblick
Eine der Hauptaufgaben eines Browsers besteht darin, Ihr DOM und CSS in Pixel auf dem Bildschirm umzuwandeln. Dazu wird ein ziemlich komplexer Prozess verwendet. Zuerst wird das Markup gelesen und daraus wird ein DOM-Baum erstellt. Ähnlich verhält es sich mit dem CSS, aus dem das CSSOM erstellt wird. Das DOM und das CSSOM werden dann kombiniert und wir erhalten eine Struktur, auf deren Grundlage wir einige Pixel zeichnen können.
Der Malprozess selbst ist interessant. In Chrome wird dieser kombinierte DOM- und CSS-Baum von einer Software namens Skia gerastert. Wenn Sie schon einmal mit dem canvas
-Element gearbeitet haben, wird Ihnen die Skia-API sehr vertraut vorkommen. Es gibt viele Funktionen im moveTo
- und lineTo
-Stil sowie eine Reihe erweiterter Funktionen. Im Grunde werden alle Elemente, die gerendert werden müssen, in eine Sammlung von Skia-Aufrufen zusammengefasst, die ausgeführt werden können. Die Ausgabe besteht aus einer Reihe von Bitmaps. Diese Bitmaps werden auf die GPU hochgeladen, die sie dann zusammensetzt, um das endgültige Bild auf dem Bildschirm zu erzeugen.

Wichtig ist, dass die Arbeitslast von Skia direkt von den Stilen beeinflusst wird, die Sie auf Ihre Elemente anwenden. Wenn Sie algorithmisch anspruchsvolle Stile verwenden, muss Skia mehr Arbeit leisten. Colt McAnlis hat einen Artikel darüber geschrieben, wie sich CSS auf das Gewicht der Seitendarstellung auswirkt. Lesen Sie ihn, um mehr zu erfahren.
Die Malarbeiten dauern jedoch ihre Zeit und wenn wir sie nicht reduzieren, überschreiten wir unser Frame-Budget von etwa 16 ms. Nutzer werden fehlende Frames bemerken und das als Ruckeln wahrnehmen, was sich letztendlich negativ auf die Nutzerfreundlichkeit unserer App auswirkt. Das ist nicht unser Ziel. Sehen wir uns an, was zu Nachbesserungen führt und was wir dagegen tun können.
Scrollen
Wenn Sie im Browser nach oben oder unten scrollen, müssen die Inhalte neu gerendert werden, bevor sie auf dem Bildschirm angezeigt werden. Im Idealfall ist das nur ein kleiner Bereich. Aber selbst dann können auf die zu zeichnenden Elemente komplexe Stile angewendet werden. Nur weil Sie eine kleine Fläche streichen müssen, bedeutet das nicht, dass es schnell geht.
Wenn Sie sehen möchten, welche Bereiche neu gemalt werden, können Sie in den Chrome-DevTools die Funktion „Paint Rectangles anzeigen“ verwenden. Klicken Sie dazu einfach auf das kleine Zahnrad rechts unten. Wenn Sie die Entwicklertools geöffnet haben, interagieren Sie einfach mit der Seite. Sie sehen dann blinkende Rechtecke, die anzeigen, wo und wann Chrome einen Teil Ihrer Seite gerendert hat.

Die Scrollleistung ist entscheidend für den Erfolg Ihrer Website. Nutzer bemerken es sofort, wenn das Scrollen auf Ihrer Website oder in Ihrer App nicht flüssig funktioniert, und das gefällt ihnen nicht. Daher ist es für uns wichtig, dass die Bildaktualisierung beim Scrollen möglichst gering ist, damit Nutzer keine Ruckler sehen.
Ich habe bereits einen Artikel zur Scrollleistung geschrieben. Sehen Sie sich diesen an, wenn Sie mehr über die Details der Scrollleistung erfahren möchten.
Interaktionen
Interaktionen sind eine weitere Ursache für Malarbeiten: Mouseover, Klicks, Berührungen, Ziehen. Jedes Mal, wenn der Nutzer eine dieser Interaktionen ausführt, z. B. den Mauszeiger bewegt, muss Chrome das betroffene Element neu zeichnen. Ähnlich wie beim Scrollen sinkt die Framerate, wenn eine große und komplexe Darstellung erforderlich ist.
Jeder möchte schöne, flüssige Interaktionsanimationen. Deshalb müssen wir noch einmal prüfen, ob die Stile, die sich in unserer Animation ändern, zu viel Zeit in Anspruch nehmen.
Eine unglückliche Kombination

Was passiert, wenn ich scrolle und gleichzeitig die Maus bewege? Es ist durchaus möglich, dass ich unbeabsichtigt mit einem Element „interagiere“, während ich daran vorbeiscrolle, und so eine teure Farbgebung auslöse. Das könnte wiederum mein Frame-Budget von etwa 16,7 ms überschreiten (die Zeit, die wir unterschreiten müssen, um 60 Frames pro Sekunde zu erreichen). Ich habe eine Demo erstellt, um Ihnen genau zu zeigen, was ich meine. Wenn Sie scrollen und die Maus bewegen, sollten die Hover-Effekte sichtbar werden. Sehen wir uns an, was die Chrome-Entwicklertools dazu sagen:

Im Bild oben sehen Sie, dass die DevTools die Malaktion registrieren, wenn ich den Mauszeiger auf einen der Blöcke bewege. Ich habe in meiner Demo einige sehr schwere Stile verwendet, um das zu verdeutlichen, und stoße daher gelegentlich an mein Frame-Budget heran. Ich möchte diese Malarbeiten auf keinen Fall unnötigerweise machen, vor allem nicht beim Scrollen, wenn noch andere Arbeit ansteht.
Wie können wir das verhindern? Die Lösung ist ziemlich einfach umzusetzen. Der Trick besteht darin, einen scroll
-Handler hinzuzufügen, der die Hover-Effekte deaktiviert und einen Timer für die Reaktivierung festlegt. Das bedeutet, dass beim Scrollen keine teuren Interaktions-Paints ausgeführt werden müssen. Wenn Sie lange genug angehalten haben, können Sie 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 setzen voraus, dass diese Klasse vorhanden ist:
/* Expect the hover class to be on the body
before doing any hover effects */
.hover .block:hover {
…
}
Das war's auch schon!
Fazit
Die Renderingleistung ist entscheidend für die Nutzerfreundlichkeit Ihrer Anwendung. Sie sollten immer darauf achten, dass die Arbeitslast für das Malen unter 16 ms bleibt. Dazu sollten Sie die Entwicklertools während des gesamten Entwicklungsprozesses verwenden, um Engpässe zu identifizieren und zu beheben, sobald sie auftreten.
Unbeabsichtigte Interaktionen, insbesondere bei Elementen mit vielen Malelementen, können sehr kostspielig sein und die Renderingleistung beeinträchtigen. Wie Sie gesehen haben, können wir das mit einem kleinen Code-Snippet beheben.
Sehen Sie sich Ihre Websites und Anwendungen an. Könnten sie einen kleinen Schutzanstrich vertragen?