Ein tiefer Einblick in die CSS Contain-Eigenschaft

Avatar of Travis Almand
Travis Almand am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

Im Vergleich zur Vergangenheit sind moderne Browser wirklich effizient geworden, wenn es darum geht, das verworrene Netz aus HTML-, CSS- und JavaScript-Code, das eine typische Webseite bietet, zu rendern. Es dauert nur Millisekunden, um den Code, den wir ihm geben, in etwas zu rendern, das die Leute nutzen können.

Was könnten wir als Front-End-Entwickler tun, um dem Browser beim Rendern noch schneller zu helfen? Es gibt die üblichen Best Practices, die bei unserer modernen Toolchain so leicht zu vergessen sind – insbesondere in Fällen, in denen wir möglicherweise nicht so viel Kontrolle über den generierten Code haben. Wir könnten unser CSS unter Kontrolle halten, zum Beispiel mit weniger und einfacheren Selektoren. Wir könnten unser HTML unter Kontrolle halten; den Baum flacher mit weniger Knoten und insbesondere weniger Kindern halten. Wir könnten unser JavaScript unter Kontrolle halten; dabei aber vorsichtig mit unseren HTML- und CSS-Manipulationen sein.

Tatsächlich helfen moderne Frameworks wie Vue und React bei diesem letzten Punkt schon eine ganze Menge.

Ich möchte eine CSS-Eigenschaft untersuchen, die wir verwenden können, um dem Browser zu helfen, herauszufinden, welche Berechnungen er in Bezug auf die Priorität reduzieren oder vielleicht sogar ganz überspringen kann.

Diese Eigenschaft heißt contain. So definiert MDN diese Eigenschaft:

Die CSS-Eigenschaft contain erlaubt es einem Autor anzugeben, dass ein Element und sein Inhalt so weit wie möglich unabhängig vom Rest des Dokumentenbaums sind. Dies ermöglicht es dem Browser, Layout, Stil, Paint, Größe oder jede Kombination davon für einen begrenzten Bereich des DOM und nicht die gesamte Seite neu zu berechnen, was zu offensichtlichen Leistungsvorteilen führt.

Eine einfache Betrachtungsweise dessen, was diese Eigenschaft bietet, ist, dass wir dem Browser Hinweise über die Beziehungen der verschiedenen Elemente auf der Seite geben können. Nicht unbedingt kleinere Elemente, wie Absätze oder Links, sondern größere Gruppen wie Abschnitte oder Artikel. Im Wesentlichen sprechen wir über Containerelemente, die Inhalte halten – auch Inhalte, die dynamischer Natur sein können. Denken Sie an eine typische SPA, bei der dynamische Inhalte auf der gesamten Seite eingefügt und entfernt werden, oft unabhängig von anderen Inhalten auf der Seite.

Ein Browser kann die Zukunft von Layout-Änderungen auf der Webseite, die durch das Einfügen und Entfernen von Inhalten durch JavaScript auf der Seite entstehen können, nicht vorhersagen. Selbst einfache Dinge wie das Hinzufügen eines Klassennamens zu einem Element, das Animieren eines DOM-Elements oder das Ermitteln der Abmessungen eines Elements können einen Reflow und Repaint der Seite verursachen. Solche Dinge können teuer sein und sollten vermieden oder zumindest so weit wie möglich reduziert werden.

Entwickler können die Zukunft gewissermaßen vorhersagen, da sie mögliche zukünftige Änderungen aufgrund des UX-Designs der Seite kennen, z. B. wenn der Benutzer auf eine Schaltfläche klickt, um Daten in ein Div einzufügen, das sich irgendwo in der aktuellen Ansicht befindet. Wir wissen, dass dies eine Möglichkeit ist, aber der Browser nicht. Wir wissen auch, dass die Möglichkeit besteht, dass das Einfügen von Daten in dieses Div visuell oder anderweitig nichts an anderen Elementen auf der Seite ändert.

Browserentwickler haben viel Zeit investiert, um den Browser für die Bewältigung solcher Situationen zu optimieren. Es gibt verschiedene Möglichkeiten, dem Browser in solchen Situationen zu helfen, aber direktere Hinweise wären hilfreich. Die contain-Eigenschaft gibt uns eine Möglichkeit, diese Hinweise zu geben.

Die verschiedenen Möglichkeiten des Containments

Die Eigenschaft contain hat drei Werte, die einzeln oder in Kombination miteinander verwendet werden können: size, layout und paint. Sie hat auch zwei Kurzschreibwerte für gängige Kombinationen: strict und content. Betrachten wir die Grundlagen jedes einzelnen.

Bitte beachten Sie, dass es für jeden dieser Werte eine Reihe von Regeln und Sonderfällen gibt, die in der Spezifikation behandelt werden. Ich stelle mir vor, dass diese in den meisten Situationen nicht von großer Bedeutung sein werden. Wenn Sie jedoch ein unerwünschtes Ergebnis erzielen, kann ein schneller Blick in die Spezifikation hilfreich sein.

Es gibt auch einen style-Containment-Typ in der Spezifikation, der in diesem Artikel nicht behandelt wird. Der Grund dafür ist, dass der style-Containment-Typ derzeit als wenig wertvoll angesehen wird und vom Entfernen aus der Spezifikation bedroht ist.

Größen-Containment

size-Containment ist tatsächlich einfach zu erklären. Wenn ein Container mit diesem Containment an den Layoutberechnungen beteiligt ist, kann der Browser einiges überspringen, da er die Kinder dieses Containers ignoriert. Es wird erwartet, dass der Container eine festgelegte Höhe und Breite hat; andernfalls kollabiert er, und das ist das Einzige, was bei der Berechnung des Seitenlayouts berücksichtigt wird. Er wird so behandelt, als hätte er keinerlei Inhalt.

Man bedenke, dass Nachfahren ihren Container in Bezug auf die Größe beeinflussen können, abhängig von den Stilen des Containers. Dies muss bei der Layoutberechnung berücksichtigt werden; bei size-Containment wird dies höchstwahrscheinlich nicht berücksichtigt. Sobald die Größe des Containers in Bezug auf die Seite ermittelt wurde, wird das Layout seiner Nachfahren berechnet.

size-Containment bietet nicht wirklich viele Optimierungsmöglichkeiten. Es wird normalerweise mit einem der anderen Werte kombiniert.

Obwohl ein Vorteil darin bestehen könnte, JavaScript zu helfen, das die Nachfahren des Containers basierend auf der Größe des Containers verändert, wie z. B. bei einer Container-Abfrage. Unter bestimmten Umständen kann die Veränderung von Nachfahren basierend auf der Größe des Containers dazu führen, dass sich die Größe des Containers nach der Veränderung der Nachfahren ändert. Da eine Änderung der Containergröße eine weitere Änderung der Nachfahren auslösen kann, könnten Sie in einer Schleife von Änderungen enden. size-Containment kann helfen, diese Schleife zu verhindern.

Hier ist ein völlig konstruiertes Beispiel für dieses Konzept der Größenänderungsschleife

In diesem Beispiel führt das Klicken auf die Start-Schaltfläche dazu, dass sich die rote Box zu vergrößern beginnt, basierend auf der Größe der lila Eltern-Box plus fünf Pixel. Wenn sich die lila Box in der Größe anpasst, teilt ein Resize Observer dem roten Quadrat mit, dass es sich wieder basierend auf der Größe des Elternteils vergrößern soll. Dies führt dazu, dass sich die Elternbox wieder vergrößert und so weiter. Der Code stoppt diesen Vorgang, sobald die Elternbox größer als 300 Pixel wird, um die Endlosschleife zu verhindern.

Die Reset-Schaltfläche stellt natürlich alles wieder her.

Durch Klicken auf die Checkbox „Größen-Containment setzen“ werden unterschiedliche Dimensionen und das size-Containment auf der lila Box eingestellt. Wenn Sie nun auf die Start-Schaltfläche klicken, passt sich die rote Box an die Breite der lila Box an. Zwar überquillt sie die Elternbox, aber darum geht es, dass sie sich nur einmal vergrößert und stoppt; es gibt keine Schleife mehr.

Wenn Sie auf die Schaltfläche „Container vergrößern“ klicken, wird die lila Box breiter. Nach der Verzögerung passt sich die rote Box entsprechend an. Wenn Sie die Schaltfläche erneut klicken, kehrt die lila Box zu ihrer ursprünglichen Größe zurück und die rote Box passt sich dann wieder an.

Obwohl es möglich ist, dieses Verhalten ohne die Verwendung des Containments zu erreichen, werden Sie die Vorteile verpassen. Wenn eine solche Situation oft auf der Seite auftreten kann, hilft das Containment bei den Seitenlayoutberechnungen. Wenn sich Nachfahren intern innerhalb des Containments ändern, verhält sich der Rest der Seite so, als hätten sich die Änderungen nie ereignet.

Layout-Containment

layout-Containment teilt dem Browser mit, dass externe Elemente weder das interne Layout des Container-Elements beeinflussen, noch das interne Layout des Container-Elements externe Elemente beeinflusst. Wenn der Browser also Layoutberechnungen durchführt, kann er davon ausgehen, dass die verschiedenen Elemente mit dem Layout-Containment keine Auswirkungen auf andere Elemente haben. Dies kann die Anzahl der durchzuführenden Berechnungen reduzieren.

Ein weiterer Vorteil ist, dass verwandte Berechnungen verzögert oder mit geringerer Priorität behandelt werden können, wenn der Container außerhalb des Bildschirms liegt oder verdeckt ist. Ein Beispiel aus der Spezifikation ist

[…] zum Beispiel, wenn die Container-Box sich am Ende einer Block-Container-Box befindet und Sie den Anfang der Block-Container-Box betrachten.

Die Container mit layout-Containment werden zu einer Containing Box für absolute oder fixed positionierte Nachfahren. Dies wäre dasselbe wie das Anwenden einer relative Position auf den Container. Beachten Sie also, wie die Nachfahren des Containers durch die Anwendung dieser Art von Containment beeinflusst werden können.

Ähnlich verhält es sich mit dem Container, der einen neuen Stapelkontext erhält, so dass z-index genauso verwendet werden kann, als ob eine relative, absolute oder fixed Position angewendet worden wäre. Das Setzen der Eigenschaften top, right, bottom oder left hat jedoch keine Auswirkungen auf den Container.

Hier ist ein einfaches Beispiel dafür

Klicken Sie auf die Box und das layout-Containment wird umgeschaltet. Wenn das layout-Containment angewendet wird, verschieben sich die beiden lila Linien, die absolut positioniert sind, nach innen in die lila Box. Das liegt daran, dass die lila Box zu einem Containing Block mit dem Containment wird. Eine weitere Sache, die zu beachten ist, ist, dass der Container nun über den grünen Linien gestapelt ist. Das liegt daran, dass der Container nun einen neuen Stapelkontext hat und diesen Regeln entsprechend folgt.

Paint-Containment

paint-Containment teilt dem Browser mit, dass keines der Kinder des Containers jemals außerhalb der Grenzen der Container-Box-Dimensionen gemalt wird. Dies ist ähnlich dem Hinzufügen von overflow: hidden; zum Container, aber mit einigen Unterschieden.

Zum einen erhält der Container die gleiche Behandlung wie unter layout-Containment: Er wird zu einem Containing Block mit seinem eigenen Stapelkontext. Das Haben von positionierten Kindern innerhalb von paint-Containment respektiert also den Container in Bezug auf die Platzierung. Wenn wir die layout-Containment-Demo oben duplizieren und stattdessen paint-Containment verwenden würden, wäre das Ergebnis weitgehend dasselbe. Der Unterschied besteht darin, dass die lila Linien den Container bei angewendetem Containment nicht überlaufen würden, sondern am border-box des Containers abgeschnitten würden.

Ein weiterer interessanter Vorteil von paint-Containment ist, dass der Browser die Nachfahren dieses Elements bei Paint-Berechnungen überspringen kann, wenn er erkennen kann, dass der Container selbst nicht im Viewport sichtbar ist. Wenn der Container nicht im Viewport ist oder auf irgendeine Weise verdeckt ist, ist garantiert, dass seine Nachfahren ebenfalls nicht sichtbar sind. Als Beispiel denken Sie an ein Navigationsmenü, das normalerweise außerhalb des linken Bildschirmrands der Seite sitzt und beim Klicken auf eine Schaltfläche hineingeschoben wird. Wenn sich dieses Menü in seinem normalen Zustand außerhalb des Bildschirms befindet, überspringt der Browser einfach das Malen seines Inhalts.

Containments, die zusammenarbeiten

Diese drei Containments bieten verschiedene Möglichkeiten, Teile der vom Browser durchgeführten Rendering-Berechnungen zu beeinflussen. size-Containment teilt dem Browser mit, dass dieser Container bei Änderungen seines Inhalts keine Positionsverschiebungen auf der Seite verursachen soll. layout-Containment teilt dem Browser mit, dass die Nachfahren dieses Containers keine Layout-Änderungen an Elementen außerhalb seines Containers verursachen sollen und umgekehrt. paint-Containment teilt dem Browser mit, dass der Inhalt dieses Containers niemals außerhalb der Dimensionen des Containers gemalt wird und, wenn der Container verdeckt ist, der Inhalt gar nicht erst gemalt werden muss.

Da jeder dieser Typen unterschiedliche Optimierungen bietet, ist es sinnvoll, einige davon zu kombinieren. Die Spezifikation erlaubt dies tatsächlich. Wir könnten zum Beispiel layout und paint zusammen als Werte für die contain-Eigenschaft verwenden, so:

.el {
  contain: layout paint;
}

Da dies eine so offensichtliche Sache ist, bietet die Spezifikation tatsächlich zwei Kurzschreibwerte

KurzschreibweiseLangschreibweise
contentlayout paint
strictlayout paint size

Der Wert content wird am häufigsten in einem Webprojekt mit einer Reihe von dynamischen Elementen verwendet, wie z. B. großen, mehrteiligen Containern, deren Inhalte sich im Laufe der Zeit oder durch Benutzeraktivität ändern.

Der Wert strict wäre nützlich für Container, die eine definierte Größe haben, die sich auch bei Inhaltsänderungen niemals ändert. Sobald sie platziert sind, behalten sie ihre beabsichtigte Größe bei. Ein einfaches Beispiel dafür ist ein Div, das externe Werbeinhalte von Drittanbietern in branchenüblichen Dimensionen enthält, die keine Beziehung zum Rest der Seite DOM-seitig haben.

Leistungsverbesserungen

Dieser Teil des Artikels ist schwer zu erklären. Das Problem ist, dass es nicht viele visuelle Aspekte der Leistungsvorteile gibt. Die meisten Vorteile sind Optimierungen im Hintergrund, die dem Browser helfen zu entscheiden, was bei einer Layout- oder Paint-Änderung zu tun ist.

Als Versuch, die Leistungsvorteile der contain-Eigenschaft zu demonstrieren, habe ich ein einfaches Beispiel erstellt, das die font-size eines Elements mit mehreren Kindern ändert. Eine solche Änderung würde normalerweise eine Neu-Layoutierung auslösen, die auch zu einem erneuten Rendern der Seite führen würde. Das Beispiel deckt die Contain-Werte none, content und strict ab.

Die Radio-Buttons ändern den Wert der contain-Eigenschaft, die auf die lila Box in der Mitte angewendet wird. Die Schaltfläche „Schriftgröße ändern“ schaltet die font-size des Inhalts der lila Box um, indem sie Klassen wechselt. Leider ist dieser Klassenwechsel ebenfalls ein potenzieller Auslöser für eine Neu-Layoutierung. Wenn Sie neugierig sind, hier ist eine Liste von Situationen in JavaScript und dann eine ähnliche Liste für CSS, die solche Layout- und Paint-Berechnungen auslösen. Ich wette, es gibt mehr, als Sie denken.

Mein völlig unwissenschaftlicher Prozess bestand darin, den Containment-Typ auszuwählen, eine Performance-Aufzeichnung in den Entwicklertools von Chrome zu starten, auf die Schaltfläche zu klicken, auf die Änderung der font-size zu warten und dann die Aufzeichnung nach einer weiteren Sekunde oder so zu stoppen. Ich habe dies dreimal für jeden Containment-Typ durchgeführt, um mehrere Aufzeichnungen vergleichen zu können. Die Zahlen für diese Art von Vergleich liegen jeweils im Bereich von wenigen Millisekunden, aber es gibt genügend Unterschiede, um ein Gefühl für die Vorteile zu bekommen. In einer realeren Situation könnten die Zahlen potenziell ganz anders aussehen.

Aber es gibt ein paar Dinge zu beachten, die über die reinen Zahlen hinausgehen.

Beim Betrachten der Aufzeichnung würde ich den relevanten Bereich in der Zeitleiste finden und mich dort konzentrieren, um die Aufgabe auszuwählen, die die Änderung abdeckt. Dann würde ich mir das Ereignisprotokoll der Aufgabe ansehen, um die Details zu erfahren. Die protokollierten Ereignisse waren: Stil neu berechnen, Layout, Layer-Baum aktualisieren, Paint und Layer zusammenstellen. Die Summe der Zeiten all dieser Ereignisse ergibt die Gesamtzeit der Aufgabe.

DevTools showing set time at 27.9 milliseconds which is the same as the total time to recalculate styles.
Das Ereignisprotokoll ohne Containment.

Eine Sache, die für die beiden Containment-Typen zu beachten ist, ist, dass das Paint-Ereignis zweimal protokolliert wurde. Dazu komme ich gleich.

DevTools showing set time at 13.8 milliseconds which is the same as the total time to recalculate styles.

Abschluss der Aufgabe

Hier sind die Gesamtzeiten für die drei Containment-Typen, jeweils drei Durchläufe

ContainmentDurchlauf 1Durchlauf 2Durchlauf 3Durchschnitt
none24 ms33,8 ms23,3 ms27,03 ms
content13,2 ms9 ms9,2 ms10,47 ms
strict5,6 ms18,9 ms8,5 ms11 ms

Die meiste Zeit wurde für das Layout aufgewendet. Es gab hier und da Spitzen in den Zahlen, aber denken Sie daran, dass dies unwissenschaftliche Anekdotenergebnisse sind. Tatsächlich hatte der zweite Durchlauf von strict-Containment ein deutlich höheres Ergebnis als die anderen beiden Durchläufe; ich habe es trotzdem aufgenommen, weil solche Dinge in der realen Welt vorkommen. Vielleicht hat sich die Musik, die ich zu dieser Zeit gehört habe, während dieses Durchlaufs von Lied zu Lied geändert, wer weiß. Aber man sieht, dass die anderen beiden Durchläufe viel schneller waren.

Anhand dieser Zahlen können Sie also beginnen zu sehen, dass die contain-Eigenschaft dem Browser hilft, effizienter zu rendern. Stellen Sie sich nun vor, meine kleine Änderung multipliziert sich mit den vielen Änderungen, die am DOM und an der Gestaltung einer typischen dynamischen Webseite vorgenommen werden.

Wo es interessanter wird, sind die Details des Paint-Ereignisses.

Layout einmal, Paint zweimal

Bleiben Sie bei mir. Ich verspreche, es wird Sinn ergeben.

Ich werde die obige Demo als Grundlage für die folgenden Beschreibungen verwenden. Wenn Sie mitverfolgen möchten, gehen Sie zur Vollversion der Demo und öffnen Sie die DevTools. Beachten Sie, dass Sie die Details des „Frames“ und nicht die des „Haupt-Timelines“ öffnen müssen, wenn Sie das Performance-Tool ausführen, um zu sehen, was ich beschreiben werde.

Showing frame details open and main details closed in DevTools.
Frame-Details geöffnet und Hauptdetails geschlossen in DevTools

Ich mache eigentlich Screenshots von der „fullpage“-Version, da die DevTools mit dieser Version besser funktionieren. Das gesagt, die normale „full“-Version sollte die grob gleiche Vorstellung vermitteln.

Das Paint-Ereignis wurde im Ereignisprotokoll für die Aufgabe, die überhaupt kein Containment hatte, nur einmal ausgelöst. Typischerweise dauerte das Ereignis nicht zu lange, von 0,2 ms bis 3,6 ms. Die tieferen Details machen es interessant. In diesen Details wird vermerkt, dass der Bereich des Paints die gesamte Seite war. Im Ereignisprotokoll wird, wenn Sie mit der Maus über das Paint-Ereignis fahren, die Seite sogar den Bereich der Seite hervorheben, der bemalt wurde. Die Abmessungen sind in diesem Fall so groß wie Ihr Browser-Viewport. Es wird auch der Layer-Root des Paints vermerkt.

Showing DevTools paint calculation of 0.7 milliseconds.
Paint-Ereignisdetails

Beachten Sie, dass der Seitenbereich links im Bild hervorgehoben ist, sogar außerhalb der lila Box. Rechts daneben sind die Abmessungen des Paints auf dem Bildschirm. Das ist ungefähr die Größe des Viewports in diesem Fall. Für einen zukünftigen Vergleich beachten Sie #document als Layer-Root.

Denken Sie daran, dass Browser das Konzept von Layern für bestimmte Elemente haben, um beim Malen zu helfen. Layer sind normalerweise für Elemente, die sich aufgrund eines neuen Stapelkontexts überlappen könnten. Ein Beispiel dafür ist die Art und Weise, wie das Anwenden von position: relative; und z-index: 1; auf ein Element dazu führt, dass der Browser dieses Element als neuen Layer erstellt. Die contain-Eigenschaft hat denselben Effekt.

Es gibt einen Bereich in den DevTools namens „Rendering“, der verschiedene Werkzeuge bietet, um zu sehen, wie der Browser die Seite rendert. Wenn Sie die Checkbox „Layer-Ränder“ auswählen, sehen wir je nach Containment unterschiedliche Dinge. Wenn das Containment auf none gesetzt ist, sollten Sie außer den üblichen statischen Webseiten-Layern keine weiteren Layer sehen. Wählen Sie content oder strict, und Sie können sehen, wie die lila Box in ihren eigenen Layer umgewandelt wird und sich die anderen Layer der Seite entsprechend verschieben.

Layer ohne Containment
Layer mit Containment

Es ist auf dem Bild vielleicht schwer zu erkennen, aber nach Auswahl von content-Containment wird die lila Box zu ihrem eigenen Layer und die Seite hat eine Verschiebung der Layer hinter der Box. Beachten Sie auch, dass in der oberen Abbildung die Layer-Linie über der Box verläuft, während in der zweiten Abbildung die Layer-Linie unter der Box liegt.

Ich habe zuvor erwähnt, dass sowohl content als auch strict dazu führen, dass der Paint zweimal ausgelöst wird. Das liegt daran, dass zwei Malprozesse aus zwei unterschiedlichen Gründen durchgeführt werden. In meiner Demo malt das erste Ereignis die lila Box und das zweite den Inhalt der lila Box.

Typischerweise malt das erste Ereignis die lila Box und meldet die Abmessungen dieser Box als Teil des Ereignisses. Die Box ist nun ihr eigener Layer und genießt die damit verbundenen Vorteile.

Das zweite Ereignis ist für den Inhalt der Box, da es sich um scrollbare Elemente handelt. Wie die Spezifikation erklärt; da der Stapelkontext garantiert ist, können scrollbare Elemente in einen einzigen GPU-Layer gemalt werden. Die im zweiten Ereignis gemeldeten Abmessungen sind höher, nämlich die Höhe der scrollbaren Elemente. Möglicherweise sogar schmaler, um Platz für die Scrollleiste zu schaffen.

Erstes Paint-Ereignis mit Content-Containment
Zweites Paint-Ereignis mit Content-Containment

Beachten Sie den Unterschied in den Abmessungen rechts bei beiden dieser Bilder. Auch der Layer-Root für beide Ereignisse ist main.change anstelle von #document, das oben zu sehen war. Die lila Box ist ein main-Element, daher wurde nur dieses Element bemalt, im Gegensatz zum gesamten Dokument. Sie sehen, wie die Box hervorgehoben wird, im Gegensatz zur gesamten Seite.

Der Vorteil davon ist, dass normalerweise, wenn scrollbare Elemente in Sicht kommen, sie gemalt werden müssen. Scrollbare Elemente in Containment sind bereits gemalt und müssen nicht erneut gemalt werden, wenn sie in Sicht kommen. Wir erhalten also auch einige Optimierungen beim Scrollen.

Auch dies ist in der Demo zu sehen.

Zurück zum Rendering-Tab. Diesmal kreuzen Sie stattdessen „Scrolling-Performance-Problem“ an. Wenn das Containment auf none gesetzt ist, überlagert Chrome die lila Box mit einer Overlay, die als „repaints on scroll“ beschriftet ist.

DevTools zeigt „repaints on scroll“ ohne Containment

Wenn Sie dies live sehen möchten, aktivieren Sie die Option „Paint flashing“.

Bitte beachten Sie: Wenn blinkende Farben auf dem Bildschirm für Sie in irgendeiner Weise problematisch sein könnten, ziehen Sie bitte in Betracht, die Option „Paint flashing“ nicht anzukreuzen. In dem von mir beschriebenen Beispiel ändert sich auf der Seite nicht viel, aber wenn man diese aktiviert lässt und andere Seiten besucht, können die Reaktionen unterschiedlich sein.

Mit aktiviertem Paint-Blinken sollten Sie einen Paint-Indikator sehen, der den gesamten Text innerhalb der lila Box bedeckt, wann immer Sie darin scrollen. Ändern Sie dann das Containment auf content oder strict und scrollen Sie erneut. Nach dem ersten anfänglichen Paint-Blinken sollte es nie wieder erscheinen, aber die Scrollleiste zeigt beim Scrollen Indikationen von Painting.

Paint-Blinken aktiviert und Scrollen ohne Containment
Paint-Blinken und Scrollen mit Content-Containment

Beachten Sie auch, dass das Overlay „repaints on scroll“ bei beiden Formen des Containments verschwunden ist. In diesem Fall hat das Containment uns nicht nur eine Leistungssteigerung beim Malen, sondern auch beim Scrollen gebracht.

Eine interessante zufällige Entdeckung

Als ich mit der obigen Demo experimentierte und herausfand, wie die Farb- und Scroll-Performance-Aspekte funktionierten, stieß ich auf ein interessantes Problem. In einem Test hatte ich eine einfache Box in der Mitte der Seite, aber mit minimalem Styling. Es war im Wesentlichen ein Element, das mit viel Textinhalt scrollt. Ich wandte die content-Containment auf das Container-Element an, aber ich sah die oben beschriebenen Scroll-Performance-Vorteile nicht.

Der Container wurde mit dem Overlay "repaints on scroll" (Neuzeichnungen beim Scrollen) markiert und die Farbaufhellung war die gleiche wie bei keiner angewendeten Containment, obwohl ich sicher wusste, dass content-Containment auf den Container angewendet wurde. Also begann ich, meinen einfachen Test mit der stärker gestylten Version zu vergleichen, die ich oben besprochen habe.

Schließlich sah ich, dass, wenn die background-color des Containers transparent ist, die Vorteile der Scroll-Performance des Containments nicht eintreten.

Ich führte einen ähnlichen Performance-Test durch, bei dem ich die font-size des Inhalts ändern würde, um das Neuanordnen und Neufärben auszulösen. Beide Tests hatten ungefähr die gleichen Ergebnisse, wobei der einzige Unterschied darin bestand, dass der erste Test eine transparente background-color hatte und der zweite Test eine ordnungsgemäße Hintergrundfarbe. Rein rechnerisch scheinen die Hintergrundberechnungen immer noch performanter zu sein; nur die Farbereignisse sind unterschiedlich. Es scheint, dass das Element mit einer transparenten background-color keine eigene Ebene in den Farb-Berechnungen wird.

Der erste Testlauf hatte nur ein Farbereignis im Ereignisprotokoll. Der zweite Testlauf hatte die beiden Farbereignisse, wie ich es erwartet hatte. Ohne diese Hintergrundfarbe scheint der Browser zu entscheiden, den Ebenenaspekt des Containments zu überspringen. Ich fand sogar heraus, dass das Vortäuschen von Transparenz durch die Verwendung der gleichen Farbe wie die Farbe hinter dem Element ebenfalls funktioniert. Meine Vermutung ist, dass, wenn der Hintergrund des Containers transparent ist, er auf das zurückgreifen muss, was darunter liegt, was es unmöglich macht, den Container von seiner eigenen Farbebene zu trennen.

Ich habe eine weitere Version der Test-Demo erstellt, die die background-color des Container-Elements von transparent auf die gleiche Farbe wie die Hintergrundfarbe des Body-Elements ändert. Hier sind zwei Screenshots, die die Unterschiede bei der Verwendung der verschiedenen Optionen im Rendering-Panel in DevTools zeigen.

Rendering-Panel mit transparentem background-color

Sie sehen die aktivierten Kontrollkästchen und das Ergebnis für den Container. Selbst mit angewendeter Content-Containment hat die Box "repaints on scroll" sowie das grüne Overlay, das das Malen beim Scrollen zeigt.

Rendering-Panel mit angewendeter background-color

Im zweiten Bild sehen Sie, dass die gleichen Kontrollkästchen aktiviert sind und ein anderes Ergebnis für den Container. Das Overlay "repaints on scroll" ist verschwunden und das grüne Overlay für das Malen ist ebenfalls verschwunden. Sie sehen das Farb-Overlay auf der Scrollleiste, um zu zeigen, dass es aktiv war.

Fazit: Stellen Sie sicher, dass Sie Ihrem Container eine Form von Hintergrundfarbe geben, wenn Sie Containment anwenden, um alle Vorteile zu nutzen.

Hier ist, was ich für den Test verwendet habe

Das ist das Ende der Seite

Dieser Artikel hat die Grundlagen der CSS-contain-Eigenschaft mit ihren Werten, Vorteilen und potenziellen Leistungssteigerungen behandelt. Es gibt einige ausgezeichnete Vorteile bei der Anwendung dieser Eigenschaft auf bestimmte Elemente in HTML; welche Elemente dies benötigen, bleibt Ihnen überlassen. Zumindest ist das, was ich verstanden habe, da ich keine spezifischen Anleitungen kenne. Die allgemeine Idee ist, sie auf Elemente anzuwenden, die andere Elemente enthalten, insbesondere solche mit einer gewissen Dynamik.

Einige mögliche Szenarien: Grid-Bereiche eines CSS-Grids, Elemente, die Inhalte von Drittanbietern enthalten, und Container mit dynamischen Inhalten basierend auf Benutzerinteraktion. In diesen Fällen sollte die Verwendung der Eigenschaft keinen Schaden anrichten, vorausgesetzt, Sie versuchen nicht, ein Element einzuschließen, das tatsächlich auf irgendeine Weise von einem anderen Element außerhalb dieses Containments abhängt.

Die Browserunterstützung ist sehr stark. Safari ist der einzige Ausreißer zu diesem Zeitpunkt. Sie können die Eigenschaft trotzdem verwenden, da der Browser den Code einfach ohne Fehler überspringt, wenn er die Eigenschaft oder ihren Wert nicht versteht.

Also, fangen Sie ruhig an, Ihre Sachen einzuschließen!