CSS Containment und content-visibility für schnelleres Rendering
60fps
ms
Performance · Rendering · CSS · Hyvä Theme
CSS Containment und content-visibility für schnelleres Rendering
Rendering-Arbeit gezielt überspringen statt sie nur zu beschleunigen

Lange Produktlisten, Facettenseiten und Kommentarbereiche zwingen den Browser dazu, tausende Elemente zu layouten und zu malen, obwohl nur ein Bruchteil davon sichtbar ist. Die CSS Eigenschaften contain und content visibility geben der Rendering Engine gezielt Kontext, welche Bereiche isoliert und welche komplett übersprungen werden können, ohne dabei Layout Shifts zu verursachen.

14 Min. Lesezeit contain · content-visibility · contain-intrinsic-size Magento 2.4.8 · Hyvä Theme · Chrome DevTools

1. Warum Rendering-Arbeit die eigentliche Bremse ist

Jeder Browser durchläuft nach dem Parsen des HTML dieselbe Pipeline: Style-Berechnung, Layout, Paint und Composite. Auf einer Seite mit tausenden DOM-Knoten, etwa einer langen Produktliste oder einem Kommentarbereich mit hunderten Einträgen, wird diese Pipeline zum Flaschenhals, weil der Browser standardmäßig annimmt, dass sich jede Änderung an einem Element auf beliebig viele andere Elemente auswirken kann. Ein einzelnes display-Toggle oder ein nachgeladenes Bild kann deshalb ein Layout des gesamten Dokuments auslösen, selbst wenn die Änderung nur einen kleinen, klar abgegrenzten Bereich betrifft.

Genau hier setzt CSS Containment an: Es erlaubt Entwicklern, dem Browser explizit mitzuteilen, dass ein Element und sein Teilbaum unabhängig vom Rest des Dokuments sind. Das ist keine visuelle Eigenschaft wie display oder overflow, sondern eine reine Optimierungs-Direktive: Sie verändert nicht, wie ein Element aussieht, sondern wie teuer es für den Browser ist, Änderungen daran zu verarbeiten. In Kombination mit content-visibility wird daraus ein Werkzeug, das nicht nur isoliert, sondern Rendering-Arbeit für nicht sichtbare Bereiche vollständig überspringt.

2. Die contain-Eigenschaft: layout, paint, size und strict im Detail

Die contain-Eigenschaft kennt mehrere Werte, die einzeln oder kombiniert gesetzt werden. contain: layout macht ein Element zu einer eigenen Layout-Wurzel: Floats, Margin-Collapsing und Positionierungskontexte aus dem Innenraum wirken sich nicht mehr auf Geschwister-Elemente außerhalb aus, und Layout-Änderungen innerhalb der Box zwingen den Browser nicht mehr, den Rest des Dokuments neu zu berechnen. contain: paint clippt den sichtbaren Inhalt an der Box-Grenze, ähnlich wie overflow: hidden, erzeugt zusätzlich einen neuen Stacking- und Containing-Block-Kontext und signalisiert dem Browser, dass außerhalb der Box nichts gemalt werden muss.

contain: size entkoppelt die Größe eines Elements von seinem Inhalt: Der Browser muss die Kindelemente nicht mehr rendern, um die Höhe der Box zu kennen, benötigt dafür aber eine explizite Höhe über CSS oder contain-intrinsic-size, sonst kollabiert die Box auf null. contain: strict ist die Kurzform für layout paint size style und liefert maximale Isolation, während contain: content dieselbe Kombination ohne size nutzt und damit sicherer ist, wenn die Höhe nicht vorab bekannt ist. Genau diese Content-Variante bildet die Grundlage von content-visibility.


/* Basic containment: isolate layout and paint for an independent widget */
.sidebar-widget {
  contain: layout paint;
}

/* Full isolation including size, requires an explicit height */
.chat-panel {
  contain: strict;
  height: 480px;
}

/* Content containment (layout + paint + style), height stays flexible */
.comment-thread {
  contain: content;
}

/* Style containment prevents CSS counters/quotes from leaking,
   use with caution since it also isolates counter-reset scopes */
.faq-item {
  contain: style;
}

3. content-visibility: auto: Rendering-Arbeit für Off-Screen-Inhalte überspringen

content-visibility: auto baut direkt auf contain: content auf und geht einen entscheidenden Schritt weiter: Solange das Element nicht in der Nähe des sichtbaren Viewports ist, überspringt der Browser Layout, Paint und den kompletten Rendering-Aufwand für dessen Inhalt vollständig, so als wäre die Sichtbarkeit auf hidden gesetzt. Sobald das Element in die Nähe des Viewports scrollt, wechselt der Browser automatisch zurück in den normalen Rendering-Modus, berechnet Layout und Paint nach und zeigt den Inhalt an, ohne dass JavaScript eingreifen muss.

Der Unterschied zu display: none ist entscheidend: Bei display: none wird das Element komplett aus dem Rendering entfernt und muss beim Wiedereinblenden vollständig neu aufgebaut werden. content-visibility: auto behält dagegen einen internen Zustand, der DOM-Baum bleibt vollständig vorhanden, Formulareingaben und Scroll-Positionen innerhalb des Bereichs überleben, und nur die teure Rendering-Arbeit wird verschoben. Für manuelles Ein- und Ausblenden ganzer Bereiche existiert zusätzlich der Wert content-visibility: hidden, der denselben Zustandserhalt bietet, aber nicht automatisch anhand der Sichtbarkeit im Viewport umschaltet.


/* Skip rendering work for product cards far outside the viewport */
.product-list-item {
  content-visibility: auto;
  contain-intrinsic-size: auto 480px;
}

/* Manual show/hide that preserves internal state, unlike display: none */
.accordion-panel[data-collapsed="true"] {
  content-visibility: hidden;
}

.accordion-panel[data-collapsed="false"] {
  content-visibility: visible;
}

4. contain-intrinsic-size gegen Layout Shifts

Sobald ein Element per content-visibility: auto nicht gerendert wird, kennt der Browser dessen tatsächliche Höhe nicht, weil er den Inhalt nicht berechnet hat. Ohne weitere Angabe nimmt er eine Höhe von null an, wodurch die Scrollbar springt, sobald Elemente in den Viewport eintreten und plötzlich ihre echte Höhe annehmen, ein klassischer Cumulative-Layout-Shift-Fall. contain-intrinsic-size löst dieses Problem, indem es eine Platzhaltergröße für den nicht gerenderten Zustand definiert, üblicherweise die durchschnittliche Höhe der jeweiligen Komponente aus realen Messungen.

Die moderne Syntax contain-intrinsic-size: auto 480px kombiniert das Schlüsselwort auto mit einem Fallback-Wert: Nachdem ein Element einmal sichtbar gerendert wurde, merkt sich der Browser die tatsächlich gemessene Größe und verwendet sie beim erneuten Verlassen des Viewports als präziseren Platzhalter, statt wieder auf den statischen Fallback-Wert zurückzufallen. Das reduziert Layout Shifts besonders bei heterogenen Listen mit unterschiedlich hohen Einträgen, etwa Produktkarten mit variabler Anzahl an Badges oder Kommentaren mit unterschiedlich langem Text.

5. Praxisfälle: lange Produktlisten und Kommentarbereiche

Der klassische Anwendungsfall in Magento- und Hyvä-Shops ist die Produktlistenseite (PLP) mit mehreren hundert Ergebnissen, die serverseitig gerendert oder per Infinite Scroll nachgeladen werden. Ohne Containment berechnet der Browser bei jeder DOM-Änderung, etwa dem Nachladen weiterer Produkte oder dem Umschalten eines Filters, potenziell das Layout der gesamten Liste neu. Mit content-visibility: auto auf jeder einzelnen Produktkarte reduziert sich die initiale Rendering-Zeit spürbar, weil nur die im Viewport sichtbaren Karten tatsächlich gelayoutet und gemalt werden, der Rest bleibt inaktiv, bis er gebraucht wird.

Ein zweiter starker Anwendungsfall sind Kommentarbereiche und Bewertungslisten mit tief verschachtelten Antworten. Solche Bereiche enthalten oft hunderte Text-Blöcke mit Avatar-Bildern, Zeitstempeln und verschachtelten Antwort-Threads, die zusammen einen erheblichen Layout-Aufwand verursachen, obwohl beim initialen Seitenaufruf nur wenige Kommentare tatsächlich sichtbar sind. Containment auf Thread-Ebene sorgt hier dafür, dass die Time-to-Interactive der Seite nicht von tief verschachtelten, unsichtbaren Kommentaren beeinträchtigt wird.


<!-- Hyva phtml: product grid item with content-visibility applied -->
<?php foreach ($block->getProductCollection() as $product): ?>
    <div class="product-card [content-visibility:auto] [contain-intrinsic-size:auto_480px] rounded-xl border border-gray-200 p-4">
        <img
            src="<?= $escaper->escapeUrl($product->getImageUrl()) ?>"
            width="280"
            height="280"
            loading="lazy"
            class="w-full h-auto object-cover rounded-lg"
            alt="<?= $escaper->escapeHtmlAttr($product->getName()) ?>"
        >
        <p class="mt-3 font-semibold text-sm"><?= $escaper->escapeHtml($product->getName()) ?></p>
        <p class="text-red-700 font-bold"><?= $block->getFormattedPrice($product) ?></p>
    </div>
<?php endforeach; ?>

6. Integration in Hyvä-Komponenten und Tailwind CSS

Tailwind CSS v4 nutzt einen CSS-first-Ansatz, wodurch sich contain und content-visibility entweder als beliebige Werte direkt in Klassennamen einsetzen lassen, etwa [content-visibility:auto], oder als wiederverwendbare Utility-Klasse in der Theme-CSS-Datei definieren lassen. Für Hyvä-Komponenten empfiehlt sich Letzteres, weil Produktkarten, Kommentar-Items und Facetten-Listen meist als eigene phtml-Templates existieren, die diese Klasse an mehreren Stellen im Theme wiederverwenden.

Wichtig ist, Containment nicht wahllos auf jedes Element zu setzen: Ein Container mit contain: layout darf keine Kinder enthalten, die bewusst über seine Grenzen hinausragen sollen, etwa Tooltips oder Dropdown-Menüs mit position: absolute, da diese sonst am Containment-Block der Karte statt am Viewport positioniert werden. Für interaktive Elemente innerhalb einer Produktkarte, etwa ein Schnellansicht-Overlay, sollte das Overlay deshalb außerhalb des per contain isolierten Containers im DOM liegen oder per Alpine.js an document.body teleportiert werden.


/* Tailwind v4 CSS-first: reusable containment utility for Hyva components */
@layer components {
  .cv-card {
    content-visibility: auto;
    contain-intrinsic-size: auto 420px;
  }

  .cv-comment {
    content-visibility: auto;
    contain-intrinsic-size: auto 180px;
    contain: content;
  }
}

/* Facet sidebar: layout containment prevents filter toggles
   from triggering a reflow of the whole product grid */
.facet-sidebar {
  contain: layout paint;
}

7. Browser-Support und Fallback-Strategien

Die Basis-Eigenschaft contain wird von allen aktuellen Browsern seit mehreren Jahren unterstützt und lässt sich bedenkenlos produktiv einsetzen. content-visibility ist in allen Chromium-basierten Browsern (Chrome, Edge, Opera) vollständig implementiert, in Firefox seit Version 125 verfügbar, in Safari dagegen erst seit den jüngeren WebKit-Versionen mit eingeschränktem Support. Der entscheidende Vorteil: Browser ohne Unterstützung ignorieren die unbekannte Eigenschaft einfach und rendern den Inhalt normal, es gibt keinen funktionalen Bruch, nur einen Performance-Unterschied.

Für Browser ohne content-visibility-Support lässt sich derselbe Effekt manuell mit einem IntersectionObserver nachbilden: Elemente außerhalb eines definierten Root-Margins erhalten display: none oder ein reduziertes Rendering, sobald sie den Viewport verlassen. Diese Lösung ist deutlich aufwendiger zu pflegen und erreicht nicht dieselbe Performance wie die native Browser-Implementierung, eignet sich aber als Übergangslösung für Projekte, die noch ältere Safari-Versionen unterstützen müssen. Mit CSS.supports('content-visibility', 'auto') lässt sich das Feature zur Laufzeit zuverlässig erkennen.


// Feature detection and IntersectionObserver fallback
// for browsers without native content-visibility support
if (!CSS.supports('content-visibility', 'auto')) {
  const items = document.querySelectorAll('.product-card');

  const observer = new IntersectionObserver((entries) => {
    entries.forEach((entry) => {
      // Toggle a class instead of display:none to keep layout stable
      entry.target.classList.toggle('is-offscreen', !entry.isIntersecting);
    });
  }, {
    root: null,
    rootMargin: '600px 0px',
    threshold: 0,
  });

  items.forEach((item) => observer.observe(item));
}

8. Messen mit Chrome DevTools: Rendering-Panel und Performance-Trace

Der zuverlässigste Weg, den Effekt von Containment zu belegen, führt über das Performance-Panel in Chrome DevTools: Ein Trace vor und nach dem Einsatz von content-visibility: auto zeigt direkt in der Flame-Chart, wie stark sich die aufsummierte Zeit für Layout und Recalculate Style reduziert. Bei langen Produktlisten sind Reduktionen der initialen Rendering-Zeit von 50 % und mehr keine Seltenheit, weil der Browser nur noch die tatsächlich sichtbaren Karten verarbeitet, statt die gesamte Liste im Voraus zu layouten.

Zusätzlich hilft das Rendering-Panel (über die DevTools-Befehlspalette mit „Show Rendering" erreichbar) mit der Option „Layout Shift Regions": Farbige Overlays markieren jeden erkannten Layout Shift direkt im Viewport und machen sichtbar, ob ein falsch geschätzter contain-intrinsic-size-Wert eine Scrollbar-Sprung verursacht. Die „Paint flashing"-Option zeigt zusätzlich, welche Bereiche der Seite tatsächlich neu gemalt werden, ein direkter visueller Beleg dafür, dass Containment außerhalb der Box keine Paint-Arbeit mehr auslöst.

9. Containment-Werte im direkten Vergleich

Jede Containment-Variante isoliert einen anderen Aspekt des Renderings und bringt ein eigenes Risiko mit, wenn sie unbedacht eingesetzt wird. Die folgende Übersicht fasst zusammen, wann welcher Wert sinnvoll ist.

Eigenschaft Rendering-Effekt Risiko bei falscher Nutzung Empfohlener Einsatz
contain: layout Isoliert Layout-Berechnungen Absolut positionierte Kinder werden geclippt Widgets mit eigenem Layout-Kontext
contain: paint Kein Paint außerhalb der Box Tooltips/Dropdowns wirken abgeschnitten Karten mit klar definierter Box
contain: size Kein Reflow durch Kindinhalte Ohne feste Höhe kollabiert die Box auf 0 Immer mit expliziter Höhe kombinieren
contain: strict Maximale Isolation (layout+paint+size+style) Style-Containment bricht Counter/Quotes Vollständig unabhängige Komponenten
content-visibility: auto Überspringt Rendering von Off-Screen-Inhalt Ohne contain-intrinsic-size springt die Scrollbar Lange Listen, Kommentarbereiche
contain-intrinsic-size Reserviert stabile Platzhaltergröße Falscher Schätzwert verursacht CLS Immer mit realistischer Durchschnittshöhe setzen

In der Praxis werden diese Werte fast immer kombiniert eingesetzt: content-visibility: auto übernimmt implizit contain: layout paint style, sodass zusätzlich nur noch contain-intrinsic-size für eine stabile Platzhaltergröße gesetzt werden muss. Reines contain ohne content-visibility bleibt sinnvoll für Bereiche, die zwar isoliert, aber nicht aus dem Rendering herausgenommen werden sollen, etwa interaktive Widgets, die dauerhaft sichtbar bleiben.

Mironsoft

Rendering-Performance und Hyvä-Optimierung für Magento-Shops

Rendering-Arbeit gezielt reduzieren?

Wir analysieren die Rendering-Pipeline eures Magento-Shops, identifizieren teure Layout- und Paint-Bereiche und setzen Containment sowie content-visibility gezielt in euren Hyvä-Komponenten um.

Rendering-Audit

Performance-Trace-Analyse, Identifikation teurer Layout-Bereiche

Content-Visibility-Integration

contain und content-visibility in Produktlisten und Kommentaren

Hyvä-Komponenten-Optimierung

Tailwind-Utilities und Alpine.js-Interaktionen ohne Layout Shift

10. Zusammenfassung

CSS Containment und content-visibility lösen ein strukturelles Problem der Browser-Rendering-Pipeline: Ohne explizite Grenzen muss der Browser bei jeder Änderung im Zweifel das gesamte Dokument neu layouten, selbst wenn nur ein kleiner, isolierter Bereich betroffen ist. contain: layout paint size style markiert Elemente als unabhängig, content-visibility: auto geht einen Schritt weiter und überspringt Rendering-Arbeit für Off-Screen-Inhalte vollständig, ohne dass JavaScript dafür manuell Elemente aus dem DOM entfernen muss.

Der entscheidende Baustein für stabile Layouts ist contain-intrinsic-size: Ohne eine realistische Platzhaltergröße für nicht gerenderte Bereiche verursacht content-visibility: auto selbst Layout Shifts, statt sie zu verhindern. In Kombination mit korrekt gesetzten Platzhaltern liefert diese Technik gerade bei langen Produktlisten und Kommentarbereichen spürbare, mit Chrome DevTools messbare Verbesserungen der initialen Rendering-Zeit, ganz ohne zusätzliches JavaScript oder Virtualisierungs-Bibliotheken.

CSS Containment und content-visibility, das Wichtigste auf einen Blick

contain isoliert Rendering

layout, paint, size und style einzeln oder als strict/content kombinierbar.

content-visibility überspringt Arbeit

Off-Screen-Bereiche werden nicht gelayoutet oder gemalt, bis sie nahe am Viewport sind.

contain-intrinsic-size gegen CLS

Platzhaltergröße reservieren, idealerweise mit dem auto-Schlüsselwort für gemessene Werte.

Messen & Fallback

Chrome DevTools Performance-Panel für Belege, IntersectionObserver als Fallback für ältere Browser.

11. FAQ: CSS Containment und content-visibility

1Was ist der Unterschied zwischen contain und content-visibility?
contain isoliert Rendering-Aspekte, rendert den Inhalt aber weiterhin. content-visibility: auto baut darauf auf und überspringt zusätzlich das gesamte Rendering außerhalb des Viewports.
2Was macht content-visibility: auto genau?
Verhindert Layout und Paint für Off-Screen-Inhalte, behält aber den DOM-Zustand vollständig bei und rendert automatisch neu, sobald das Element in Viewport-Nähe scrollt.
3Wie verhindere ich Layout Shifts beim Einsatz von content-visibility?
Mit contain-intrinsic-size als Platzhaltergröße. Die auto-Variante merkt sich zusätzlich die real gemessene Höhe nach dem ersten Rendern.
4Welche Werte kann contain-intrinsic-size annehmen?
Ein oder zwei Längenwerte, optional mit auto davor. Mit auto übernimmt der Browser nach dem ersten Rendern die tatsächlich gemessene Größe als Platzhalter.
5Ist content-visibility: hidden dasselbe wie display: none?
Nein. content-visibility: hidden behält den internen Rendering-Zustand bei, ein erneutes Einblenden ist deutlich günstiger als der Neuaufbau nach display: none.
6Welche Browser unterstützen contain und content-visibility?
contain seit Jahren überall verfügbar. content-visibility vollständig in Chromium, in Firefox ab Version 125, in Safari erst mit eingeschränktem Umfang.
7Wie messe ich den Effekt von content-visibility in Chrome DevTools?
Über das Performance-Panel per Vorher-Nachher-Trace und das Rendering-Panel mit Layout Shift Regions zur Kontrolle von contain-intrinsic-size.
8Funktioniert die Browser-Suche (Strg+F) noch in Bereichen mit content-visibility: auto?
Ja, moderne Browser rendern gefundene Bereiche automatisch temporär, sodass der Inhalt trotz übersprungenem Rendering durchsuchbar bleibt.
9Für welche Magento- oder Hyvä-Seiten lohnt sich content-visibility besonders?
Lange Produktlistenseiten, Kommentar- und Bewertungsbereiche mit verschachtelten Antworten sowie Facettenseiten mit umfangreichen Filterlisten.
10Kann contain-intrinsic-size: auto die Schätzung automatisch verbessern?
Ja, nach dem ersten sichtbaren Rendern speichert der Browser die gemessene Größe und nutzt sie bei erneutem Verlassen als präziseren Platzhalter.