CSS3 a detekce podporovaných vlastností pomocí pravidla @supports

Proti každému webdesignerovi stojí celá fronta prohlížečů s dosti rozličnou podporou kaskádových stylů. Existují různé strategie, jak se s tímto problémem vypořádat. Jedná se nejspíš o věčný problém a detekce podporovaných vlastností se dostává přímo do CSS3.

Tento text je překladem článku Native CSS feature detection via the @supports rule, jehož autorem je Chris Mills a je zde zveřejněn pod licencí CC-BY-3.0.

Úvod

Podpora standardů v dnes používaných prohlížečích se dosti liší (od moderních prohlížečů po  křápy jako IE6), a tak nám není proti srsti nabízet různým prohlížečům odlišný kód nabízející sice odlišný, ale stále přijatelný uživatelský zážitek. Dělá se to různými způsoby, obecně se spoléhá buď na (méně spolehlivou) detekci prohlížečů nebo na (chytřejší) detekci podporovaných vlastností.

Detekci vlastností obyčejně vykonáte vlastním kódem v JavaScriptu, kterým otestujete existenci patřičné vlastnosti, metody atd. nebo pomocí nějaké knihovny, jakou je např. skvělý Modernizr. Modernizr nabízí detekci řady vlastností HTML5 a CSS3 a mechanismus pro selektivní použití CSS a JavaScriptu na základě této detekce.

Je to užitečné, ale řada lidí se sháněla po nativním mechanismu. Dobrá zpráva je, že jsme na něm začali pracovat. Tento článek popisuje CSS pravidlo  @supports, které je součástí specifikace CSS3 Conditional Rules Module Level 3, která nabízí mechanismus pro selektivní použití kaskádových stylů na základě podporovaných vlastností. Podíváme se na základní syntaxi a ukážeme si příklad.

Pozn.: @supports je zatím podporován v Opeře 12.10 a Firefoxu Aurora; prohlížeče neznající @supports budou tento blok zcela ignorovat. To znamená, že tu už pro něj máme použití, ale pokud vám nestačí, zůstaňte zatím ještě u Modernizeru.

Syntaxe @supports

@supports má podobu at-rule bloku („zavináčového pravidla“), které spustí test a vykoná CSS pravidla uvnitř bloku na základě toho, zda test vrátil true nebo ne. V tomto případě test vždy sestává z jedné nebo vícero deklarací CSS a prohlížeč vrátí true, pokud uvedené deklarace podporuje, např.:

@supports (display:flex) {
  section { display: flex }
  ...
}

Pravidla uvnitř tohoto bloku budou použita, jen pokud prohlížeč podporuje  display: flex.

@supports také podporuje klíčové slovo not, můžeme tak použít styly pouze v případě, že daná vlastnosti není podporovaná. Mohli bychom tak nabídnout alternativní styl prohlížečům nepodporujícím  display:flex:

@supports not (display: flex) {
  // alternatiní layout
  // např. pomocí float
}

@supports také podporuje klíčová slova or a and, která zajistí aplikaci stylů jen v případě, že prohlížeč projde vícero testy nebo v případě, že test projde jedním z několika odlišných testů.

Kupříkladu flexbox je bez vendor prefixu podporovaný Operou a IE10. Pro otestování, zda prohlížeč podporuje vlastnost s prefixem nebo bez prefixu, můžete zapsat:

@supports (display: -webkit-flex) or
          (display: -moz-flex) or
          (display: flex) {
  section {
    display: -webkit-flex;
    display: -moz-flex;
    display: flex;
    …
  }
}

A ještě příklad pro and: mohli byste chtít použít multi-column layout pouze v prohlížečích, které podporují neprefixované vlastnosti column-width a column-span (prohlížeče, které podporují multi-col s prefixem, prozatím nepodporují column-span, což je dost omezující):

@supports (column-width: 20rem) and (column-span: all) {
  div { column-width: 20rem }
  div h2 { column-span: all }
  div h2 + p { margin-top: 0; }
  ...
}

A nesmíme zapomenout uvést, že kombinace and, or a not je nutné uvádět s pomocí závorek, aby byly jasné jejich priority. Mohli byste chtít použít animaci zahrnující 3D transformaci pouze v prohlížečích podporujících animace a 3D transformace:

@supports ((-webkit-animation-name: my-animation) and (-webkit-transform: rotate3D(1,2,4,90deg))) or
          ((-moz-animation-name: my-animation) and (-moz-transform: rotate3D(1,2,4,90deg))) or
          ((-ms-animation-name: my-animation) and (-ms-transform: rotate3D(1,2,4,90deg))) or
          ((-o-animation-name: my-animation) and (-o-transform: rotate3D(1,2,4,90deg))) or
          ((animation-name: my-animation) and (transform: rotate3D(1,2,4,90deg))) {
  // sem přijde vaše skvělá animace
}

Malá ukázka

Abych vám předvedl použití @supports, upravím příklad z mé knihy Practical CSS3: develop and design — 3D rotující vizitka, která využívala Modernizr, aby nabídla alternativní zážitek prohlížečům bez podpory 3D a 2D transformací (jen jsem při hover zvětšil left padding, aby se odkryla zadní strana). Příklad pomocí Modernizeru si můžete zobrazit online. Na obrázcích 1 až 3 předvedu odlišný výsledek v závislosti na podpoře v prohlížečích.

Vizitka vytvořená pomocí CSS3. V prohlížečích podporujících 3D transformace se vizitka animovaně otočí

Obr. 1: V prohlížečích podporujících 3D transformace se vizitka animovaně otočí.

Vizitka vytvořená pomocí CSS3. V prohlížečích bez podpory 3D transformací, ale s podporou 2D transformací, se přední strana vizitky animovaně odsune, a tím se zobrazí i její zadní strana

Obr. 2: V prohlížečích bez podpory 3D transformací, ale s podporou 2D transformací, se přední strana vizitky animovaně odsune, a tím se zobrazí i její zadní strana.

Vizitka vytvořená pomocí CSS3. V prohlížečích bez podpory 3D a 2D transformací se přední strana vizitky bez animace posune, aby se zobrazila i zadní strana vizitky

Obr. 3: V prohlížečích bez podpory 3D a 2D transformací se přední strana vizitky jednoduše posune, aby se zobrazila i zadní strana vizitky.

V tomto příkladu jsem nabídl fallback kód prohlížečům bez podpory 3D transformací a následně i těm, které nepodporují ani 2D transformace. V našem příkladě za pomoci @supports budu postupovat opačně pomocí přístupu progressive enhancement. Napřed nabídnu základní funkčnost, která zobrazí obě dvě strany vizitky prakticky všem prohlížečům:

/* || Pro prohlížeče bez podpory 2D a 3D transformací */

#wrapper:hover #inner-wrapper #front, #wrapper:focus #inner-wrapper #front {
  margin-left: -350px;
}

Starší prohlížeče použijí tento kód a další pravidla uvnitř @supports budou ignorovat.

Přidáme pravidla pro prohlížeče s podporou 2D transformací:

/* || Pro prohlížeče podporující 2D transformace */

@supports (-webkit-transform: rotate(-30deg)) or
          (-moz-transform: rotate(-30deg)) or
          (-ms-transform: rotate(-30deg)) or
          (-o-transform: rotate(-30deg)) or
          (transform: rotate(-30deg)) {


  #inner-wrapper #front {
    -webkit-transition: 0.8s all ease-in;
    -moz-transition: 0.8s all ease-in;
    -ms-transition: 0.8s all ease-in;
    -o-transition: 0.8s all ease-in;
    transition: 0.8s all ease-in;
  }

  #wrapper:hover #inner-wrapper #front, #wrapper:focus #inner-wrapper #front {
    margin-left: 0;

    -webkit-transform: rotate(-30deg) translate(-50%,-100%);
    -moz-transform: rotate(-30deg) translate(-50%,-100%);
    -ms-transform: rotate(-30deg) translate(-50%,-100%);
    -o-transform: rotate(-30deg) translate(-50%,-100%);
    transform: rotate(-30deg) translate(-50%,-100%);
  }

}

A nakonec přidáme kód pro prohlížeče podporující 3D transformace:

/* || Pro prohlížeče podporující 3D transformace */

@supports (-webkit-transform: rotateX(0deg)) or
          (-moz-transform: rotateX(0deg)) or
          (-ms-transform: rotateX(0deg)) or
          (-o-transform: rotateX(0deg)) or
          (transform: rotateX(0deg)) {

  #front, #back {
    -webkit-backface-visibility: hidden;
    -moz-backface-visibility: hidden;
    -ms-backface-visibility: hidden;
    -o-backface-visibility: hidden;
    backface-visibility: hidden;
  }

  #front {
    -webkit-transform: rotateX(0deg);
    -moz-transform: rotateX(0deg);
    -ms-transform: rotateX(0deg);
    -o-transform: rotateX(0deg);
    transform: rotateX(0deg);
  }

  #back {
    -webkit-transform: rotateX(180deg);
    -moz-transform: rotateX(180deg);
    -ms-transform: rotateX(180deg);
    -o-transform: rotateX(180deg);
    transform: rotateX(180deg);
  }

  #wrapper:hover #inner-wrapper, #wrapper:focus #inner-wrapper {
    -webkit-transform: rotateX(180deg);
    -moz-transform: rotateX(180deg);
    -ms-transform: rotateX(180deg);
    -o-transform: rotateX(180deg);
    transform: rotateX(180deg);
  }

  #wrapper:hover #inner-wrapper #front, #wrapper:focus #inner-wrapper #front {
    -webkit-transform: none;
    -moz-transform: none;
    -ms-transform: none;
    -o-transform: none;
    transform: none;
  }

}

Výsledek můžete vidět online.

window.supportsCSS();

Opera 12.10 je v tuhle chvíli jediný prohlížeč, který vedle supports podporuje i odpovídající javascriptové API, které umožňuje spouštět kód na základě podpory CSS vlastností. Přepíšu úvodní příklad do JavaScriptu:

var flexy = window.supportsCSS('display:flex');

if(flexy) {
  alert('Podporuji Flexbox!');
}

Ve specifikaci můžete najít syntaxi CSS.supports a nikoliv window.supportsCSS. To protože jsme implementovali starší verzi specifikace a navíc jsme se u použití globálního objektu CSS báli konfliktů se stávajícími weby. Ještě se ukáže, jak se tenhle problém vyřeší.

Shrnutí

A tím naše představení @supports končí. Jedná se rozhodně o zajímavou vlastnost pomocí které můžete spolehlivě detekovat podporované vlastnosti a nabízet dle toho příslušný CSS kód. Problémem jsou starší prohlížeče nepodporující @supports, kterým musíte nabídnout alternativní cestu. Doufáme, že to bylo pro vás přínosné a předpokládáme, že tahle vlastnost začne být časem mnohem víc užitečná. Dejte nám vědět, co si o ní myslíte, váš feedback nám můžete napsat do mailing listu www-style.

Vystudoval jsem biochemii. Vymyslel a založil Zdroják. Aktuálně ho vedu. Nejsem váš hodný tatínek, který vás bude brát za ručičku, ale zlý moderátor diskusí. Smiřte se s tím!

Věděli jste, že nám můžete zasílat zprávičky? (Jen pro přihlášené.)

Komentáře: 6

Přehled komentářů

VfB Nightly design
Martin Hassman Re: Nightly design
Čelo Re: Nightly design
Futrál Autor článku zřejmě zaspal
churchyard Řeší to jen podporu dané vlastnosti?
Bubák Re: Řeší to jen podporu dané vlastnosti?
Zdroj: https://www.zdrojak.cz/?p=3745