Martin Michálek Martin Michálek  – 16. 9. 2020

Už víme, že cílem CSS containmentu (a vlastnosti contain) je umožnit vylepšení výkonu prohlížeče poskytnutím předvídatelné izolace části DOMu od zbytku stránky.

Vlastnost content-visibility je na tom postavená. Vývojářům zjednodušuje práci a nenutí je chápat CSS containment do detailů.

Na rozdíl od vlastnosti contain umožňuje určit, zda prohlížeče vůbec vykreslí obsah dotčeného prvku. Její použití jim tak dovolí při počítání renderingu přeskočit náročné fáze layoutpaint.

Je to víceméně jako lazy loading pro vykreslení velkých obsahových celků. Obvykle může vhodné použití content-visibility například vylepšit čas úvodního zpracování stránky tím, že přeskočí vykreslování obsahu, který není vidět na obrazovce.

Hodnoty

Hodnota Co dělá?
visible Bez efektu. Obsah elementu se vykreslí běžným způsobem. (Výchozí hodnota.)
hidden Obsah elementu není vidět. Je to podobné jako visibility:hidden. Element není dostupný pro funkce jako najít na stránce, procházení tabulátory; nelze jej označit ani jinak zaměřit přes :focus.
auto Zapíná layout, style a paint containment. Na rozdíl od hidden jsou auto prvky stále k dispozici pro hledání, tabulátory i zaměření.

Výchozí hodnota visible nás zase tak moc nezajímá. Pojďme si však něco říct o těch dalších dvou.

Dobře, prozradím to – nejzajímavější je hodnota auto, ale nejprve něco k třetí hodnotě, která určitý potenciál má taky.

Hodnota hidden

Deklaraci content-visibility:hidden použijte, když chcete, aby obsah nebyl vyrenderován a zároveň využívat výhody uložení stavu vykreslování v mezipaměti a CSS containmentu.

Nebyl vyrenderován, nebyl vyrenderován… počkat nemáme pro tohle v CSS už jiné vlastnosti?

Srovnání s jinými typy schovávání

  • display:none
    Skryje prvek a zahodí jeho vykreslovací stav. To znamená, že skrytí prvku je z pohledu výkonu stejně drahé jako vykreslení nového prvku se stejným obsahem. display:none navíc neumožňuje na dotčeném obsahu realizovat akce typu vyhledání na stránce atd.
  • visibility:hidden
    Skryje prvek a udržuje jeho vykreslovací stav. Aktualizuje také stav vykreslování, kdykoli je to třeba, i když je skrytý. Nicméně, potomci prvku s visibility:hidden si mohou kdykoliv nastavit visibility:visible a začít se zobrazovat, což v případě content-visibility:hidden nehrozí. Prvky s visibility:hidden stále zabírají původní prostor na stránce, což prvek s content-visibility:hidden nedělá, šetří rendering díky containmentu. content-visibility navíc nepodléhá průběžnému přepočítávání layoutu. Prohlížeč musí spočítat vzhled prvku s content-visibility až v momentě, kdy jej potřebuje znovu zobrazit.
display:none visibility:hidden content-visibility:hidden
Rezervace plochy Neudržuje Udržuje Neudržuje
Stav renderingu Smaže Udržuje Udržuje poslední stav
Mohou přebít potomci Ne Ano Ne

Tabulka: Srovnání vlastností pro schovávání obsahu v CSS

Podle specifikace pro content-visibility platí, že pokud jsou jeho omezení přijatelná, může to být spolehlivější a konzistentnější způsob jak skrýt obsah prvku než vlastnost visibility.

Příklad použití content-visibility:hidden

Chcete mít v DOMu připravený kus obsahu, který uživatel nevidí a zároveň už DOM není příliš složitý, takže není nutné jej načítat AJAXem?

Může se to týkat různých pohledů v JS aplikacích (SPA), zobrazování panelů záložek a tak dále.

Pokud byste použili přepínání display:none/display:block, prohlížeč musí pokaždé prvek znovu celý přepočítat pro vykreslování a nebude k dispozici například pro hledání nebo tabulátorovou navigaci.

Pokud byste prvek umístili mimo obrazovku přes position:absolute, k dispozici pro tyhle akce bude, ale zase tyto prvky bude muset prohlížeč při každé změně ve stránce přepočítávat.

Tohle je tedy příklad, kdy content-visibility:hidden využijete.

Hodnota auto

Hodnota auto zapíná něco jako líný rendering pro části stránky, které nejsou na první pohled vidět.

Element, který má content-visibility:auto spouští containment pro vykreslovací fáze layout, stylepaint, takže může ušetřit docela dost výkonu.

Pokud je prvek mimo obrazovku (a není pro uživatele jinak relevantní - například tedy nemá fokus nebo není vybraný), získá také size containment.

Pokud je na stránce velké množství obsahu, které bude často mimo obrazovku (například dlouhý rolovatelný seznam komplexnějších prvků), je v pořádku to na tento obsah aplikovat.

Příklad s Twitterem

Ve specifikaci uvádějí příklad s Twitterem. Jednotlivé tweety jsou relativně komplexní prvky DOMu, které prohlížeč nemusí nutně vykreslovat, když jsou mimo viditelný viewport.

Nebylo by v úplně pořádku aplikovat content-visibility:auto na celý rodičovský prvek pro tweety, ale na jednotlivé tweety se to naopak velmi hodí.

Připomeňme si ale, že content-visibility:auto zapíná size containment, takže prohlížeč prvkům nerezervuje prostor ve stránce.

Takto označeným prvkům ale nějak musíme nastavit alespoň odhadovanou výšku pro vykreslení, aby prohlížeč věděl, jaké rozměry mají mít rolovací lišty. K tomu slouží vlastnost contain-intrinsic-size.

Vlastnost contain-intrinsic-size

Vlastnost, která určuje přirozenou velikost prvku, pokud je prvek ovlivněn size containmentem.

To jsou právě prvky, které mají nastaveno content-visibility:auto a vyskytují se mimo viditelnou část stránky.

Prohlížeč je vynechá z renderování, ale nezná jejich velikost (chová se jako by měly height:0), což může při posunu stránky ovlivňovat právě například velikost rolovátek.

Deklarace vypadá takto:

contain-intrinsic-size: <šířka> <výška>;

První hodnota definuje vnitřní šířku prvku, druhá vnitřní výšku. Pokud je druhá hodnota vynechána, bude výchozí výška nastavená na stejnou hodnotu jako je šířka.

Na výše uvedeném příkladu Twitteru si např. můžeme říct, že průměrný tweet je zhruba 200px vysoký a 500px široký:

.tweet {
  contain-intrinsic-size: 500px 200px
}

Podpora v prohlížečích a nástrojích

Vlastnost content-visibility podporuje Chrome od verze 85. Předpokládáme, že se to vztáhne na všechny prohlížeče založené na Chromiu, jako je Edge nebo Opera.

Firefox se jeví, že by vlastnost rád naimplementoval. Safari se neozývá.

V tuto chvíli je pro nás ale podstatná podpora vlastnosti na pomalejších zařízeních, hlavně těch mobilních. A na těch běží právě Chrome. Z nepodpory v ostatních prohlížečích si tedy těžkou hlavu dělat nemusíme. Tato vlastnost zařídí malé vylepšení pro majitele Chrome, ostatní zůstanou na původním stavu.

Je dobré si uvědomit, že externí měřící nástroje (PageSpeed Insights, SpeedCurve) obvykle běží na starších jádrech prohlížečů, takže v době psaní textu vám žádné pokroky neukáží a radost neudělají.

Příklady a testy

Vlastnost prý může ušetřit desítky až stovky milisekund při počítání vykreslování stránky. Una Kravets udělala demo, kde je vidět sedmkrát méně času, spotřebovaného při renderingu. Jan Šablatura to vyzkoušel na webu českých Novinek a teoreticky by tam prý došlo k ušetření více než 40 % renderovacího času.

Moje testy

Moje testy takto dobře ovšem nedopadly. Na sedminásobné ušetření renderingu se ne a ne dostat. Ale nějaká úspora zde být může, to ne že ne.

Testoval jsem například homepage Novinky.cz a iRozhlas.cz:

Stránka Rendering před Rendering po
Novinky.cz 113 ms 82 ms
iRozhlas.cz 330 ms 235 ms

Udělal jsem tři testy před a tři po nasazení content-visibility:auto přes Lighthouse v DevTools Chromu. Podívejte se na tabulku.

Zde je kompletní metodika:

  • Testuji stránku v Chrome DevTools, záložce Lighthouse.
  • Z výsledků rozklikávám „View Trace“ a hodnoty tedy čtu ze záložky Performance.
  • Pomocí Local Overrides upravuji kód hlavního CSS souboru.
  • Obě verze testuji s Local Overrides, aby se neprojevilo zkreslení způsobené načtením stylů z lokálního adresáře. Ve verzi testů „před“ prostě jen deklaraci zakomentuji.
  • Pro nasazení content-visibility:auto jsem vybral vždy velké části skryté mimo obrazovku na mobilech.
  • Ve výsledném profilu vybírám celou časovou osu, nikoliv předvolený výběr.

Kam se to hodí?

Určitě bych content-visibility:auto nenasazoval bezhlavě na cokoliv, o čem víte, že se bude vykreslovat mimo obrazovku. V některých mých testech vyšlo spíše zhoršení času renderingu a špatné nasazení bude mít vliv na metriku Kumulativní posun layoutu (CLS), která je součástí důležitých Core Web Vitals.

Určitě je vhodné se nad nasazením zamyslet v těchto případech:

  • Stránka má velmi komplexní DOM, např. nad 3 tisíce uzlů.
  • Čísla pro rendering jsou vysoká, obzvlášť na mobilech.
  • Mimo obrazovku jsou umístěné prvky, které spouští zlobivý JavaScript, například různé vkládané prvky sociálních sítí, včetně <iframe>.

Jako efektivnější alternativu zvažte líné načtení celé oblasti DOMu s čekáním na narolování uživatele do dané oblasti pomocí Intersection Observer. Tahle metoda může ušetřit také datový objem stránky, zmenšit DOM a často také ulehčit backendu.

V mnoha případech bude ale content-visibility:auto fungovat dobře a velmi ulehčí renderingu, hlavně na pomalých mobilech. Jen nezapomeňte testovat, testovat a testovat.

Budu rád za každé vaše zjištění, neváhejte využít komentáře.

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