Od počátku bylo základem responzivního webu CSS pravidlo @media
. Jejich nevýhoda ale je, že určují použitá pravidla podle velikosti obrazovky zařízení. Díky snaze několika designérů a vývojářů ale můžeme od roku 2022 používat i kontejnerovou podmínku @container
, která naopak určuje responzivní styl podle místa dostupného pro konkrétní DOM prvek (tzv. kontejner).
Poznámka: Od května 2021 je níže uvedená funkčnost implementována jako experimentální v nočních buildech Chrome. Očekávám, že do ostrého provozu a ostatních prohlížečů se dostane koncem tohoto roku nebo v průběhu roku 2022.
Containment aneb oddělení kontejneru od stránky
Základem kontejnerových pravidel je již (od ledna 2020) existující CSS vlastnost contain
, která dokáže konkrétní DOM prvek převést na kontejner oddělený od zbytku stránky a zajistit jeho nezávislé renderování.
Pro vytvoření responzivní komponenty je nejprve potřeba její wrapper (vnější kontejner) oddělit od zbytku stránky:
.component-wrapper {
contain: layout size style;
}
Co znamenají jednotlivé hodnoty je popsáno v článku Rychlost zpracování změn CSS.
Kontejnerová pravidla
Poté, co kontejner oddělíte, můžete na něj již začít používat pravidla @container
.
Trochu matoucí může být to, že v pravidle neuvádíte odkaz na daný kontejner, ale rovnou pracujete s jeho vnořenými prvky (children). Prohlížeč pak pravidla použije tak, že pro každý prvek najde jeho nadřazený kontejner s vlastností contain
. (Tohle je stejný princip jako když prvku nastavíte position: absolute
a prohlížeč najde nejbližšího rodiče s vlastností position: relative
, aby zjistil, kde má prvek zobrazit.)
Pokud vám vadí, že v CSS není uvedeno jméno kontejneru, můžete vytvořit pravidlo, tak, že uvede jeho jméno do definice selektoru.
//výchozí "mobilní" styl (wrapper uvádím jen pro ujasnění)
.component-wrapper > .component {
display: flex;
flex-flow: column;
//...
}
//styl pro "tablety"
@container (min-width: 768px) {
.component {
flex-flow: row;
//...
}
}
//styl pro "desktop" (grid)
@container (min-width: 992px) {
.component {
display: grid;
grid-template-rows: 1fr auto 1fr;
grid-template-columns: 1fr 2fr 1fr;
//...
}
}
Výše uvedený styl zobrazí prvky komponenty pod sebou (column flexbox), na tabletu vedle sebe (row flexbox) a na větších obrazovkách (desktop) pak použije grid pro uspořádání prvků podle potřeby.
Ale díky tomu, že místo @media
jsme použili @container
, nezáleží na skutečném rozlišení zařízení (tedy mobil, tablet, desktop), ale na tom, kde komponentu zobrazíte.
Pokud tedy danou komponentu zobrazíte v těle stránky, kde bude mít 992+px, zobrazí grid, ale když ji na desktopu vložíte do sidebaru, který má jen 400px na šířku, použije komponenta „mobilní“ layout s column flexbox. Pokud ale zobrazíte komponentu v těle stránky na 1376px se 400px sidebarem, zbude na tělo stránky jen ~970px a komponenta použije tabletový layout (row flexbox).
Pozor na to, že klíčem je, že kontejner musí mít nastaveno contain: size
, které říká, že prvek musí mít nastavenu pevnou šířku a výšku a tudíž nestačí spoléhat na to, že se kontejner přizpůsobí stránce (např. podle šířky sidebaru). Naopak, pokud chcete komponentu umístit do sidebaru, musíte jí také nastavit požadované rozměry:
.sidebar {
width: 400px;
padding: 10px;
}
.sidebar > .component-wrapper {
width: 380px; //400px - 2 * 10px padding
}
Podpora v prohlížečích
Jak už jsem psal výše, vlastnost contain
i podmínka @container
jsou nové, takže s velkou podporou nepočítejte. Vlastnost contain
je podporována jen ve Firefox a Chrome (+ Opera a Edge) z roku 2020+, takže nepočítejte s IE ani Safari. Podmínka @container
zatím není podporovány v žádném oficiálně používaném prohlížeči.
V Chrome můžete podmínku @container
zapnout v chrome://flags pod „Enable CSS Container Queries“.
Pro budoucí podporu sledujte https://caniuse.com/css-container-queries.