Ich habe einige blinde Flecken in Bezug auf CSS-bezogene Performance-Dinge. Ein Beispiel ist die will-change Eigenschaft. Es ist ein guter Name. Sie sagen dem Browser, dass eine bestimmte Eigenschaft (oder die scroll-position oder der Inhalt) äh, *wird*, sich ändern.
.el {
will-change: opacity;
}
.el.additional-hard-to-know-state {
opacity: 0;
}
Aber ist das wichtig zu tun? Ich weiß nicht. Der Punkt ist, soweit ich das verstehe, dass es `.el` dazu bringt, auf der GPU statt auf der CPU zu verarbeiten/rendern/malen, was ein Geschwindigkeitsboost ist. So ähnlich wie der klassische `transform: translate3d(0, 0, 0);` Hack. Im exakten Fall oben scheint es meinem Gehirn nicht so vorzukommen, als ob es wichtig wäre. Ich habe im Kopf, dass `opacity` eines der „billigsten“ Dinge zum Animieren ist, daher gibt es keinen besonderen Vorteil bei `will-change`. Oder vielleicht ist es auf *manchen* Browsern oder Geräten spürbar, aber auf anderen nicht? Das ist schließlich Frontend-Entwicklung.
Es gab eine Welle von Artikeln über `will-change` um 2014/2015, die vor seltsamen Verhaltensweisen warnen, wie z. B. unerwartete Änderungen im Stapelkontext und die Vorsicht, es nicht „zu viel“ zu verwenden. Es gab auch Ratschläge, dass man diese Eigenschaft niemals direkt in CSS-Stylesheets verwenden sollte; man sollte sie nur in JavaScript anwenden, bevor sich der Zustand ändert, und sie dann entfernen, wenn man sie nicht mehr benötigt.
Ich habe keine Ahnung, ob das alles noch stimmt. Tut mir leid! Ich würde gerne eine Deep Dive-Analyse von 2022 zu `will-change` lesen. Wir sind in der Lage, solche Tests durchzuführen, also setze ich es auf die Ideenliste. Aber mein Punkt ist, dass es Dinge in CSS gibt, die explizit für die Leistung entwickelt wurden und die für mich verwirrend sind, und ich wünschte, ich hätte ein vollständigeres Verständnis davon, weil sie sehr wichtige Dinge zu sein scheinen.
Nehmen Sie „Wie ich Googles Datengitter mit einer Zeile CSS 10x schneller scrollen ließ“ von Johan Isaksson. Eine 10-fache Verbesserung der Scroll-Leistung ist eine massive Sache! Wissen Sie, wie sie es behoben haben?
[…] als ich die Seite „Top linking sites“ durchsah, bemerkte ich deutliche Scroll-Verzögerungen. Dies tritt auf, wenn Sie sich entscheiden, einen größeren Datensatz (500 Zeilen) anstelle der Standardergebnisse von 10 anzuzeigen.
[…]
Was habe ich also getan? Ich habe einfach eine einzige CSS-Zeile zu der `<table>`-Anweisung imElements-Panel hinzugefügt und dabei angegeben, dass sie das Layout oder den Stil anderer Elemente auf der Seite nicht beeinflusst.
table {
contain: strict;
}
Die Eigenschaft `contain` ist eine weitere, die ich *irgendwie* verstehe, die ich aber immer noch als blinden Fleck bezeichnen würde, weil mein Gehirn nicht automatisch daran denkt, wann ich sie verwenden könnte (oder sollte?). Aber das ist schade, denn offensichtlich baue ich keine Schnittstellen, die so performant sind, wie sie sein könnten, wenn ich `contain` besser verstehen würde.
Da gibt es noch eine! Die Eigenschaft content-visibility. Das, was dem Verständnis am nächsten kam, war, nachdem ich Jake und Surmas Video dazu gesehen hatte, wo sie sie (zusammen mit `contain-intrinsic-size` und einigen seltsamen magischen Zahlen) verwendeten, um eine lange Seite *dramatisch* zu beschleunigen. Was mir nicht im Gedächtnis geblieben ist, ist, wann *ich* sie auf *meinen* Seiten verwenden sollte.
Sind alle drei dieser Funktionen Funktionen, die „da sind, wenn Sie sie brauchen“? Ist es in Ordnung, sie zu ignorieren, bis Sie Leistungsprobleme bei etwas (wie einer riesigen Seite) bemerken, und dann zu ihnen greifen, um zu versuchen, es zu lösen? Fast schon „verwenden Sie diese nicht, bis Sie sie brauchen“, sonst sind Sie im Bereich der vorzeitigen Optimierung. Das Problem dabei ist die klassische Situation, in der Sie die schlechte Leistung nicht bemerken werden, es sei denn, Sie testen aktiv auf den Geräten mit der geringsten Ausstattung.
Oder sind diese Funktionen „das ist, was modernes CSS ist, und Sie sollten sie so betrachten, wie Sie an `padding` denken“? Ich vermute, es ist eher so. Wenn Sie ein Element erstellen, von dem Sie *wissen*, dass es sich in bestimmten Bereichen nicht ändern wird, ist es wahrscheinlich sinnvoll, es zu „containen“. Wenn Sie ein Element erstellen, von dem Sie *wissen*, dass es sich in bestimmten Bereichen ändern wird, ist es wahrscheinlich sinnvoll, Browsern diese Information zur Verfügung zu stellen. Wenn Sie einen Teil einer Seite erstellen, von dem Sie wissen, dass er sich immer unter dem sichtbaren Bereich befindet, ist es wahrscheinlich sinnvoll, das Malen darauf zu vermeiden. Aber persönlich habe ich einfach nicht genug davon verstanden, um konkrete Ratschläge geben zu können.
Könnten die Leistungsberichte von DevTools oder Lighthouse diese Eigenschaften vorschlagen? Der Browser hat ein besseres Verständnis des DOM und der Render-Trees als der Entwickler, daher kann er besser identifizieren, welches Element ein Leistungsproblem verursacht und welche Art von Problem, und dann die entsprechende CSS-Funktion vorschlagen, um das Problem zu mildern.
Ich denke, Sie sind auf dem falschen Weg, wenn Sie `will-change` in Bezug auf CPU/GPU betrachten. Ein besserer Weg, es zu verstehen, ist zu erkennen, dass eine gerenderte Webseite in mehrere Ebenen unterteilt werden kann. Jede Ebene wird unabhängig in ein statisches Bild gemalt (das als Ganzes neu gemalt werden muss, wenn es sich ändert), und dann werden die Bilder übereinander komponiert.
Was die Leistungsunterschiede verursacht, sind drei Fragen
Wie viele Ebenen gibt es? Je mehr Ebenen Sie haben, desto mehr Kompositionsoperationen sind erforderlich. Aber wenn es nicht genug sind, können Änderungen innerhalb einer Ebene auftreten und diese muss öfter neu gemalt werden.
Welche Abmessungen hat jede Ebene? Je kleiner die Ebene, desto weniger Pixel müssen bei der Komposition berechnet werden.
Welcher Kompositionsalgorithmus muss verwendet werden? Wenn die Kompositionsoperation `over` ist und die obere Ebene undurchsichtig ist, werden die alten Pixel einfach mit den neuen überschrieben, keine Berechnung erforderlich, aber wenn Transparenz beteiligt ist oder sogar ein Mischalgorithmus, ist jedes Pixel das Ergebnis eines Rechenzyklus.
Browser ermitteln die optimale Aufteilung einer Seite in Ebenen für sich selbst. Die von Ihnen genannten Eigenschaften helfen bei der Beantwortung. Wenn das Setzen dieser Eigenschaften bei der Beantwortung der obigen Fragen hilft, probieren Sie es aus.
Das habe ich aus einem Vortrag von Martin Splitt von Google gelernt, der 2017 auf Deutsch und auf Englisch gehalten wurde.
Chris, ich bin ein langjähriger Leser deines Blogs und ich wollte sagen, dass ich deine demütige, ehrliche Art, über Dinge zu schreiben, die du noch nicht vollständig verstanden hast, wirklich sehr mag. Danke!!
Ja. Das ist die goldene Regel der Optimierung: Profiling, Profiling, Profiling. Dann verwenden Sie diese Eigenschaften, um die Probleme zu lösen, die Sie im Profil sehen. Wenn Sie beispielsweise sehen, dass viel Zeit für „Recalculate Style“ in Ihrem Profil anfällt, wenn viele Elemente auf dem Bildschirm sind, verwenden Sie `content: strict`.
Sie müssen nicht unbedingt auf einem langsamen Gerät testen, da das Profil aufzeigen kann, ob die relativen Zeitanteile falsch aussehen, auch wenn die absolute Verarbeitungszeit gering ist.
Ich liebte den Kommentar von ccprog. Die Idee von verschiedenen Ebenen oder Segmenten mit unterschiedlichen Änderungsgraden und wie wir den zugrunde liegenden Mechanismen (für Rendering, Malen, Überschreiben usw.) Hinweise geben können, um eine optimale Leistung zu unterstützen, ist interessant. Als Veteran erinnert mich das an die Zeit, als wir unsere Software explizit in logische Segmente aufteilten und eine „Overlay-Map“ definierten, damit das Betriebssystem wusste, welche Teile zur gleichen Zeit im Speicher sein mussten, um die beste Leistung zu erzielen, und welche ausgetauscht werden konnten, wenn sie fertig waren. All das wurde obsolet, als virtuelle Speicher-/Paging-Systeme aufkamen – die verfolgten, welche Seiten häufig aufgerufen wurden und für die Leistung im realen Speicher gehalten werden mussten. Vielleicht werden `will-change` und andere Pragmas, die wir heute verwenden, mit zukünftigen Fortschritten ähnlich in den Hintergrund treten.
Layouts und Repaints können auch mit `will-change` auftreten. Es scheint, dass der Browser nichts garantieren kann, da viele andere Parameter Optimierungen verhindern können.
Ich betrachte `will-change` eher als einen Vorschlag an Browser als eine tatsächliche Anweisung.
Ich betrachte `will-change` und `contains` in zwei getrennten Kategorien
* `will-change` kann dazu führen, dass der Browser zusätzliche Arbeit leistet, die er möglicherweise nicht von selbst getan hätte
* `contains` sagt dem Browser, dass er einige der Arbeiten (Malen oder Layout), die er normalerweise tun würde, nicht tun muss
Meiner Meinung nach ist `contains` also sicherer… aber ja, vorzeitige Optimierung sollte vermieden werden.
Komposition ist im Allgemeinen schneller als Neuzeichnen. Malen ist destruktiv, während Komposition nicht destruktiv ist. Bevor Photoshop bearbeitbare Texte hatte, gaben Sie den gewünschten Text ein und er wurde in die aktuelle Ebene rasterisiert. Wenn Sie ihn an eine andere Position verschieben, vergrößern oder seine Deckkraft ändern wollten, müssten Sie den rasterisierten Text übermalen und das Textwerkzeug erneut verwenden. Oder Sie könnten das Textwerkzeug auf einer transparenten Ebene verwenden und ihn verschieben können, ohne ihn vom Hintergrund löschen zu müssen.
Heutzutage sind Browser ziemlich gut darin, Kompositor-Ebenen automatisch zu erstellen, wenn sie sie benötigen (z. B. für `opacity` und `transform`). Aber wenn das plötzlich geschieht, sagen wir als Reaktion auf ein Benutzerereignis, gibt es eine beträchtliche Menge an Arbeit, die erledigt werden muss: den Hintergrund ohne das fragliche Element neu malen, eine neue Kompositor-Ebene zuweisen und das Element darauf malen, beide gemalten Ebenen auf die GPU verschieben und dann komponieren. All dies am Anfang eines Übergangs kann zu ein wenig Ruckeln in den ersten paar Frames führen, während diese Pixel verschoben werden. Hier kommt `will-change` ins Spiel. Es lässt Sie vorschlagen, dass der Browser diese Schritte *jetzt* ausführen soll, in Erwartung, dass er *später* eine Eigenschaft animieren, überblenden oder anderweitig ändern muss, die der Kompositor leicht handhaben kann (hauptsächlich `opacity` und `transform`). Daher ist `will-change` am vorteilhaftesten, wenn Sie vorschlagen können, dass der Browser dies vorbereitet, bevor Sie die Kompositionseigenschaften ändern müssen. Andernfalls wird er es sowieso just-in-time behandeln.
Wie ccprog anmerkt, möchten Sie `will-change` jedoch nicht unnötig hinzufügen. Das Erstellen zu vieler Kompositor-Ebenen verbraucht erheblichen Videospeicher und es gibt einen Overhead beim Übertragen von Farbänderungen auf diesen Ebenen an die Grafikkarte. Es ist keine Allzweckwaffe und kein garantierter Leistungsschub. Es hat das Potenzial, die Leistung negativ zu beeinflussen.
Zusätzlich zum Profiling können die Rendering-Optionen „Paint Flashing“ und „Layer Borders“ in den Entwicklertools aufschlussreich sein, wenn Sie versuchen herauszufinden, was der Browser tut oder wie `will-change` und `contains` die Leistung beeinflussen können.