pile of old painting needing a repaint
Tutorials |

CSS-Animation: Wie man unnötige Repaints vermeidet

martin.jpg.png

Martin

20. September 2018

»Hey, ist diese Animation irgendwie ruckelig?«
»Definitiv, ich ignoriere sie schon seit Monaten erfolgreich!«
»Was ist da los? Können wir sie flüssiger machen?«
»Ähm, keine Ahnung... Vielleicht?«

Als Frontend-Entwickler bei einem unserer Kunden habe ich genau diese Unterhaltung mit einem Teammitglied geführt. Wir sollten damals die Web-App analysieren und Ideen zur Verbesserung der UI-Performance entwickeln. Als Erstes habe ich das gemacht, was heute jeder Webentwickler machen würde: Google fragen. Leider habe ich nur wenige hilfreiche Infos zu diesem Thema gefunden. Einige – eigentlich die meisten – Erklärungen zu unserem Animationsproblem waren ziemlich unspezifisch und wirkten auf mich irgendwie mysteriös. Mir wurde schnell klar, dass solche Probleme durch verschiedene Faktoren entstehen können, oft durch eine Kombination bestimmter gängiger HTML-, CSS- und JavaScript-Muster, die einzeln keine Probleme verursachen, aber zusammen Schwierigkeiten machen können. Mein Ausgangspunkt war also nicht wirklich klar, und deshalb konnte ich keine direkte Lösung finden. Also habe ich beschlossen, erstmal zu verstehen, was genau im Browser passiert.

Der erste Schritt war ganz einfach die Nutzung der Paint flashing Option in den Chrome DevTools. Ich habe unsere verdächtig ruckelige Animation inspiziert und etwas Merkwürdiges entdeckt: Obwohl die Animation nur einen bestimmten Bereich beeinflussen sollte, hat sie – aus irgendeinem Grund – komplette (!) Seiten-Repaints verursacht. In weniger als zwei Minuten habe ich weitere Elemente auf unserer Seite gefunden, die sich ähnlich verhielten, wie diese hier:

Screencast showing examples of full page repaints when the animation is triggered
Screencast showing examples of full page repaints when the animation is triggered

Beispiele für vollständige Seiten-Repaints, wenn die Animation ausgelöst wird.

Soweit, so schlecht. Eigentlich wollte ich nur eine Animation etwas verbessern und habe stattdessen ein umfassendes Problem in unserer Web-App gefunden. Der Browser macht unnötige Arbeit und zeichnet Inhalte neu, die er gar nicht neu zeichnen müsste. Was konnte ich also mit dieser neuen Erkenntnis anfangen?

Um zu verstehen, warum sich der Browser so verhält, habe ich mich intensiv mit der Rendering-Pipeline des Browsers beschäftigt. Dazu gibt es einige gute Ressourcen. Es war vermutlich das erste Mal, dass ich wirklich verstanden habe, wie ein Browser aus Code Pixel erzeugt. Dieses Diagramm zeigt drei verschiedene Wege, die der Browser nehmen kann, um Elemente auf dem Bildschirm darzustellen:

Overview of Pixels to screen pipeline according to Google’s Web Fundamentals

Als ich dann von der dritten Option erfahren habe, hat es bei mir sofort Klick gemacht: Layout- und Painting-Schritte komplett zu vermeiden könnte die Lösung sein! Also habe ich mir den Code meiner Animation genauer angesehen. Hier eine vereinfachte Version:

Ich habe dann angefangen, die Dinge Schritt für Schritt zu optimieren. Zuerst habe ich die animierte Property von margin-left: -300px zu transform: translateX(-300px) geändert. Und das hat bereits mein Problem gelöst! Die Animation war nicht mehr ruckelig. Yeah 🎉 🎉 🎉! Ich weiß nicht, ob das FPS-Meter jetzt 60 Bilder pro Sekunde anzeigt, aber man konnte den Unterschied definitiv spüren – sogar auf einem aktuellen Laptop.

Was passiert hier? Durch die Verwendung der transform-Property erlauben wir dem Browser, den Layout- und Painting-Schritt zu überspringen. Er verschiebt einfach die bereits gezeichneten Ebenen, was als Compositing bezeichnet wird. Diese Technik wird übrigens auch häufig in Zeichentrickfilmen verwendet, um das Neuzeichnen von Bildteilen zu vermeiden, die sich nicht ändern.

Das Kompositionsverfahren wurde in den 1950er Jahren von Walt Disney erfunden, um die Produktion von Zeichentrickfilmen zu beschleunigen.

Noch einen Schritt weiter

Nun, ich hätte an dieser Stelle aufhören können, denn die Animation lief schon ziemlich flüssig. Aber das Paint-Flashing-Tool zeigte immer noch grüne Rechtecke über die ganze Seite hinweg. Ich wollte es noch weiter verbessern.

Der nächste Schritt war, die transition-Property so einzuschränken, dass nur die transform-Property animiert wird, anstatt einfach all anzugeben. Leider hat das keinen weiteren Vorteil gebracht. Es war genau wie vorher. Trotzdem finde ich es besser, die Animation einzuschränken, nur für den Fall, dass ein anderer Entwickler den Code ändern muss und versehentlich andere Eigenschaften animiert.

Bei weiteren Recherchen bin ich auf die will-change-Property gestoßen. Sie kann die Performance von CSS-Animationen verbessern, sollte aber nicht überall im Code verwendet werden, da sie die Performance auch verschlechter kann, wenn man sie zu oft einsetzt. Eine Seitennavigation ist dafür ein ziemlich guter Anwendungsfall, denke ich, weil wir wissen, dass sie häufig animiert wird. Also habe ich sie hinzugefügt.

Boom! Das Paint-Flashing war komplett verschwunden. Das bedeutet, dass wir jetzt nur noch Compositing durchführen, anstatt überall auf der Seite Repaints zu machen. Die will-change-Property verschiebt im Grunde das gesamte Element auf seine eigene Compositing-Ebene, sodass es animiert werden kann, ohne andere Elemente zu berühren. Erfolg! Aufgabe erledigt, Zeit nach Hause zu gehen 🏠. Nein, natürlich bleibe ich noch für ein Fazit...

Fazit

Ich habe viel über den Browser gelernt und kann die im Blogpost verlinkten Ressourcen sehr empfehlen. Als Webentwickler ist es sehr wichtig, über die Rendering-Pipeline Bescheid zu wissen. Ein fundiertes Wissen zu diesem Thema ermöglicht es dir, gute Lösungen für verschiedene Probleme zu finden, ohne das Gefühl zu haben, nach einer Nadel im Heuhaufen zu suchen. Und natürlich kannst du deine Kollegen beeindrucken, indem du ihnen all die technischen Diagramme in Chrome's DevTools erklärst, haha.

Übrigens

Die Website, die in diesem Blogpost vorgestellt wird, ist SevenCooks, eine alternative Plattform für vegetarisches und veganes Essen. Wir bei Peerigon versuchen sicherzustellen, dass jeder Besucher ein reichhaltiges Nutzererlebnis hat. Du kannst Rezepte mit Filtern erkunden und sie in deinem persönlichen Profil sammeln. Aber, die Seite ist nur auf Deutsch verfügbar!

Danke an Leonhard Melzer und Tanner Hoisington.

Web Development

CSS Animation

Rendering

Browsers

Devtools

Weitere Themen

Lea, 04.04.2025

Vue clever nutzen – Wiederverwendbarkeit für Einsteiger:innen

Vue

JavaScript

Reusability

DRY Principle

Components

Composables

Zum Blogartikel
Header-top-ten-mistakes-to-avoid.png

Francesca, Ricarda, 02.04.2025

Die 10 häufigsten Fehler bei der Entwicklung digitaler Produkte – und wie du sie vermeidest

MVP development

UX/UI design

product vision

agile process

user engagement

product development

Zum Blogartikel

Judith, 31.03.2025

Von der Hypothese zur echten Erkenntnis: MVPs richtig einsetzen

Zum Blogartikel