CSS vlastnost contain

Vlastností contain označujeme části stránky, které jsou izolované od zbytku. Izolujeme je proto, aby prohlížeč nemusel při změnách překreslovat celou stránku. Ušetříme tím výkon na stránkách s komplexním DOMem.

Prohlížeče se už dlouho různými způsoby snaží nepřepočítávat vzhled celé stránky při každé změně samy.

Kromě toho existují kodérské triky, jak to udělat v běžném CSS (hledejte např. „Layout Boundaries“). No a relativně novou možností je použít pro tyhle účely vlastnost contain.

Celá problematika „CSS Containmentu“ je nejzajímavější ve vlastnosti content-visibility, ale silně se využívá také v Container Queries.

Dva příklady

Vlastnost contain může ušetřit čas potřebný pro vykreslování hlavně v případech, kdy DOM obsahuje tisíce uzlů. Následující příklady proto berte jako schématické a hodně zjednodušené.

Přidání prvku do DOMu

Tuhle ukázku jsem převzal z dokumentace od Googlu. Máme následující HTML:

<section class="view">
  Home
</section>

<section class="view">
  About
</section>

A teď JavaScriptem přidáme nový prvek:

<section class="view">
  Home
</section>

<section class="view">
  About
  <div class="newly-added-element">Check me out!</div>
</section>

Přidání nového prvku spouští rovnou tři kroky procesu překreslování – styl, layout a paint. Blbé ovšem je, že se ten proces spouští pro celý DOM a celou stránku. Může pak pomoci přidání vlastnosti contain.

…

Ilustrační obrázek: Čas potřebný pro fázi layout můžeme snížit díky omezení na konkrétní boxík menšímu počtu prvku k přepočítání. Zdroj developers.google.com.

Podívejme se ještě na jednu ukázku.

Výpis článků mimo viditelnou část obrazovky

Vezměme, že na stránce máme stovky či tisíce položek typu články, produkty nebo třeba tweety. Většinu z nich uživatelé neuvidí v prvním vykresleném viewportu. Zároveň jde o samostatné a izolované prvky, které se se zbytkem stránky nijak vzájemně neovlivňují.

Takhle může vypadat jejich výpis ve stránce:

<h1>Articles</h1>
<article> … </article>
<article> … </article>

Představme si, že prvků <article> jsou zde stovky a zároveň mají složitou vnitřní DOM strukturu.

Pomocí vlastnosti contain můžeme prohlížeč informovat, ať tyto prvky vyjme z celkového vykreslování stránky:

article {
  contain: content;
}

Prohlížeči tak dáváme instrukci, že prvky .element, které „nevidí“ ve viewportu může v klidu vynechat z počítání vzhledu celé stránky.

Ušetříme tím v některých situacích slušný renderovací čas.

CodePen: cdpn.io/e/gOrMOWd

Typy „containmentu“

Zatím se mi nepovedlo najít vhodné české slovíčko pro teorii, o které se ve specifikaci mluví jako o „CSS containmentu“. Jde o soběstačné a nezávislé zapouzdření prvku, což je ale poněkud kostrbaté označení.

Známe čtyři typy zapouzdření, které jsou zároveň možné hodnoty vlastnosti contain:

Hodnota containTyp zapouzdření
sizeZapouzdření pro velikost.
Prohlížeči říkám, že velikost prvku nijak neovlivní jeho potomci. Pokud nastavíme contain:size, je potřeba v CSS také tomuto prvku nastavit nějakou velikost. Jinak prohlížeč počítá, že velikost je nulová, což nechceme. Zapouzdření velikosti samo o sobě zase tak moc výkonu při renderování neušetří.
inline-sizeZapouzdření pro „inline“ velikost.
Totéž jako size jen pro změny velikosti na vodorovné ose.
layoutZapouzdření pro rozvržení.
Říkáme tím, že se layout potomků prvku a zbytku stránky nijak vzájemně neovlivňují. Díky tomu může při zápise contain:layout prohlížeč vynechat počítání layoutu vnitřních prvků elementu a zaměřit se jen na prvek, který tuto vlastnost má nastavenou.
paintZapouzdření pro vykreslení.
Informujeme tímto, že žádný vnitřní prvek nevyčnívá ze svého rodiče. Uvedení contain:paint prohlížeči umožňuje potenciálně přeskočit vykreslení potomků, pokud je prvek mimo obrazovku.
styleZapouzdření pro styly.
Říkáme, že ovlivněný prvek vyjímáme z počítání hodnot napříč dokumentem, které provádějí vlastnosti jako counter-increment, counter-set nebo quotes.

Hodnoty vlastnosti contain jde kombinovat, takže můžete například uvést contain: style paint.

Speciální hodnoty

Za účelem zjednodušení problematiky pro nás, autory webů, přichází specifikace se speciálními hodnotami vlastnosti contain:

Hodnota containTyp zapouzdření
strictVšechny typy zapouzdření, kromě stylů.
Totéž jako zápis contain: size layout paint.
contentVšechny typy zapouzdření, kromě stylů a velikosti.
Totéž jako contain: layout paint.

Hodnota strict ušetří prohlížeči více času, ale zase musíme znát a definovat velikost prvku.

Jak to použít v praxi? Pojďme se zde vrátit k druhé ukázce – renderování desítek či stovek článků mimo viditelnou část obrazovky:

  • Pokud bychom použili contain:content, nemusíme definovat výšku jednotlivých bloků. Na druhou stranu bude prohlížeč při prvním vykreslení považovat výšku za nulovou a nevykreslí například správně velká rolovátka.
  • Pokud bychom použili contain:strict, prohlížeči musíme výšku sdělit, ale zase nenastane přepočítání velikosti rolovátka.

Vlastnost contain vytváří nové kontexty

Pokud containment použijete s hodnotami paint, strict nebo content vytvoří se nové kontexty, které je možné dělat i jinými metodami v CSS:

  • Nový obsahující blok (containing block) – pro potomky, jejichž vlastnost position je absolute nebo fixed, takže něco jako position:relative.
  • Nový kontext stohování (stacking context), ve kterém můžete nezávisle na zbytku stránky umísťovat prvky do vrstev pomocí z-index.
  • Nový kontext formátování bloku (block formatting context), který například umí obsáhnout vnitřní prvky umístěné pomocí float nebo zakáže spojování vnějších okrajů (margin).

Využít containment, konkrétně například contain:content, tedy můžete i v případě, že nechcete šetři výkon, ale usnadnit si kodérskou práci.

Podpora je plná

Vlastnost contain nepodporuje Internet Explorer, což vůbec nevadí. Všechny moderní prohlížeče v containmentu jedou s námi.

Viz také CanIUse.com/mdn-css_properties_contain

Odkazy

Pokud vás problematika containmentu zajímá více, zde je pár tipů k dalšímu studiu:

Za připomínky autor děkuje Michalovi Matuškovi.