V CSS nebo JavaScriptu se nám občas hodí napsat kód, který rozlišuje varianty podle podpory určitých CSS vlastností.
K tomu můžeme použít poměrně nové pravidlo @supports, součást specifikace „CSS Conditional Rules Module“.
S pomocí @supports je možné psát „Feature Queries“, dotazy na vlastnosti. Vezměme například ukázky s dotazem na nativní podporu layoutu typu masonry:
@supports (grid-template-rows: masonry) {
.text {
color: green;
}
}
Pokud se na ukázku podíváte v prohlížečích, které podporují vlastnost grid-template-rows a zároveň její hodnotu masonry, což je na začátku roku 2022 zatím jen Firefox Nightly, uvidíte zelený text.
Ve všech ostatních prohlížečích bude text černý.
CodePen: vrdl.in/3q7kt
Všimněte si důležité věci – pro detekování podpory se musíme dotazovat na vlastnost i její hodnotu. Takže pokud bychom se ptali na podporu vlastnosti display, musíme se zeptat například na display:block.
Logické operátory: not, and a or
Specifikace „Feature Queries“ velmi správně definuje logické operátory podle zvyklostí z jiných jazyků.
Operátor not
Velice často se nám může hodit negace a klíčové slovo not:
@supports not (display: grid) {
.box {
float: right;
}
}
Kód se aplikuje jen v těch prohlížečích, které nepodporují CSS grid.
Operátor and
Logický operátor konjunkce (tedy průnik dvou množin) – and:
@supports (display: table-cell) and (display: list-item) {
.text {
color: green;
}
}
Použijeme ho v případech, kdy musí platit všechny podmínky.
Operátor or
Další operátor – or – definuje logickou disjunkci (tedy sjednocení množin):
@supports (transform-style: preserve) or
(-moz-transform-style: preserve) {
.text {
color: green;
}
}
Podmínka je platná v případě, že prohlížeč podporuje alespoň jednu z deklarací uvedených v závorkách. To se může hodit právě pro práci s prohlížečovými prefixy, zde -moz. Píšu o tom ještě v textu níže.
Kombinování operátorů
Při kombinování operátorů se vyplatí být doslovný – vždy uvádějte závorky.
Tyto deklarace nejsou validní:
@supports display: flex {
/* Neplatné */
}
@supports (transition-property: color) or
(animation-name: foo) and
(transform: rotate(10deg)) {
/* Neplatné */
}
Tento zápis ale validní je:
@supports (display: flex) {
/* … */
}
@supports ((transition-property: color) or
(animation-name: foo)) and
(transform: rotate(10deg)) {
/* … */
}
Aby nedošlo k záměně mezi and a or, syntaxe je specifikována tak, aby byly výslovně psány jako and nebo or.
Prohlížečové prefixy
Dalším překvapením může být nutnost používat všechny prefixové vlastnosti. Pokud máte v cílové skupině uživatele prohlížečů, které vlastnost podporují jen s použitím prefixů, musíte je uvést všechny:
@supports ((box-shadow: 0 0 2px black inset) or
(-moz-box-shadow: 0 0 2px black inset) or
(-webkit-box-shadow: 0 0 2px black inset) or
(-o-box-shadow: 0 0 2px black inset)) {
/* Kód pro všechny prohlížeče podporující box-shadow,
včetně těch už historických */
}
Příklad mám ze specifikace. Dnes už byste prefixy k box-shadow nepotřebovali, takže tím kromě jiného ilustruji, že prefixy je potřeba uvádět jen tehdy, pokud byste je psali i v běžném CSS kódu.
Nejlepší je ale starost o prefixy přenechat automatizaci, konkrétně nástroji Autoprefixer.
Detekce podpory selektorů
Některé moderní prohlížeče umožňují detekovat také podporu určitých CSS selektorů. Dělají to pomocí nové funkce selector():
@supports selector(A > B) {
/* Kód pro prohlížeč, který podporuje selektor A > B */
}
Funkce selector() je součástí nové verze specifikace modulu „CSS Conditional Rules“ a podporují ji všechny moderní prohlížeče.
Řešení pro podporu detekce selektorů už dříve hledalo více autorů pomocí různých hacků. Zajímavý je například tento, který se dotazuje na podporu pseudotřídy :placeholder-shown:
.foo { color: red }
:not(*):placeholder-shown,
.foo {
color: green
}
V textu „Using Feature Detection, Conditionals, and Groups with Selectors“ světu své řešení představil „náš“ Jirka Vebr. Tož díky! vrdl.in/vebrfeature
Feature Queries v JavaScriptu
Metoda CSS.supports() vrací hodnotu true nebo false určující, zda prohlížeč danou funkci CSS podporuje nebo ne.
Toto jsou možné zápisy:
result = CSS.supports("grid-template-rows", "masonry");
result = CSS.supports("display: grid");
result = CSS.supports("(--foo: red)");
result = CSS.supports("(transform-style: preserve) or (-moz-transform-style: preserve)");
V prvním řádku vidíme verzi se dvěma parametry: v prvním je prostě hodnota a ve druhém vlastnosti.
Další tři řádky ukazují variantu, kdy do textu uvedeme DOMString rovnou s hodnotou celé podmínky.
Ti z vás, které jsem ještě neunavil detailním líčením, si možná všimli detekce autorské vlastnosti (nebo též „custom property“ či „CSS proměnné“) ve třetím řádku ((--foo: red)). Ano, i tu je možné detekovat.
→ Související: CSS proměnné nebo také autorské vlastnosti
CSS hacky a Progressive Enhancement
Udělejme si teď pro zajímavost výpravu do historie. @supports totiž navazuje na silnou epochu „CSS hacků“, kterou jsme k všeobecné nelibosti prožívali zhruba v první dekádě 21. století.
Tenkrát nebylo možné v CSS podporu vlastností detekovat, proto kodérky a kodéři hledali chyby v prohlížečích při implementaci CSS pravidel, tedy zápis, který funguje v určitých prohlížečích a v jiných naopak ne.
Asi nejznámější byl podtržítkový hack:
.box {
/* Kód pro všechny prohlížeče: */
position: fixed;
/* Kód jen pro IE5+: */
_position: absolute;
}
Pokud by vás tahle dnes už nechvalně známá praxe zajímala, píšou o ní hezky v přehledu CSS hacků na v těch časech populárním magazínu Interval.cz. vrdl.in/mo8hx
Brrr, úplně mi běhá mráz po zádech, když si představím, že v té době jsem nakódoval opravdu hodně webů. Jak bych byl tehdy za @supports vděčný!
CSS hacky a dnes @supports jsou důležitou částí zásadní webařské techniky: postupného vylepšování (Progressive Enhancement). Funguje asi takto:
- Vyrobíte základní řešení fungující ve všech prohlížečích.
- Nad tím postavíte lepší řešení fungující jen v některých prohlížečích.
Mezi jednotlivými řešeními je detekce vlastností (nikoliv prohlížeče!), například právě pomocí dotazu @supports.
Výsledkem je, že nějaké řešení máte pro nejširší možnou skupinu zařízení. Pro web ideální.
Podpora @supports a limity použitelnosti
První omezené použití @supports vychází z principů fungování prohlížečů – „Feature Queries“ nelze použít ke kontrole, zda prohlížeč vlastnost, hodnotu nebo selektor podporuje správně a bez chyb.
Pokud si totiž prohlížeč „myslí“, že vlastnost umí, vrátí na dotaz kladnou odpověď. Ale soudruzi z NDR mohli někde v implementaci vlastnosti udělat chybu.
Dalším omezením je samotná podpora vlastnosti, v tomto případě však záleží na použití: @supports nepodporuje vůbec žádný Internet Explorer.
caniuse.com/css-featurequeries
Je ovšem otázka, jak moc tahle chybějící podpora vadí. Mně vůbec. A hned vám řeknu proč.
Internet Explorer je totiž skoro vždy ve skupině prohlížečů, které tu či onu vlastnost nezvládají. Proto vůbec nevadí, když nerozumí ani otázce, zda vlastnost zvládá…
Ukažme si problém s Explorerem ještě na jednom příkladu.
Závěrečná ukázka s detekcí CSS gridu
Řekněme, že máme HTML s jedním kontejnerem a třemi položkami:
<div class="container">
<div class="item">Item 1</div>
<div class="item">Item 2</div>
<div class="item">Item 3</div>
</div>
Chtěli bychom položky jednoduše umístit vedle sebe, což s pomocí flexboxu uděláme takto:
.container {
display: flex;
}
.item {
flex: 1;
}
Z nějakého důvodu bychom ovšem v moderních prohlížečích chtěli použít CSS grid:
.container {
display: grid;
grid-template-columns: repeat(3, 1fr);
}
Je to samozřejmě naprosto schůdné, použijeme detekci pomocí @supports, dotazu na vlastnosti:
@supports (display:grid) {
.container {
display: grid;
grid-template-columns: repeat(3, 1fr);
}
}
Na pohled to bude vypadat stejně. Takhle jednoduchý kód se samozřejmě nevyplatí psát ve flexboxu i gridu. Budu ale předpokládat, že jde o základ pro využití pokročilejších vlastností gridu, kterých má požehnaně.
Dvě verze pro dvě kategorie prohlížečů. To nám snadno umožní Feature Queries, dotazy na vlastnosti.
Tady nastává moment, pro který jsme si v demíčku šli. MSIE nejenže nezná display:grid, ale zároveň nezná @supports, takže tento blok kódu vynechá ze zpracování. A to je dobře.
CodePen: vrdl.in/pdc3h
V CodePenu uvidíte v prohlížečích podporujících grid zelené písmo. V ostatních je to červeně.
A to je, prosím pěkně, úplně vše, co jsem vám chtěl říct. Máte-li po ruce zajímavou ukázku využití @supports, neváhejte mě ji svěřit do komentářů.