Martin Michálek Martin Michálek  – 23. 5. 2017

Nové atributy řeší potřebu autorů stránek zobrazovat v různých kontextech designu různé varianty obrázků.

Změna kontextu v může vypadat takto:

  1. Změna layoutu pro jinou velikost obrazovky.
  2. Zobrazení stránky na zařízeních s displeji typu Retina (různými poměry device-pixel-ratio).

Do budoucna může jít třeba ještě o změnu úrovně zoomu na stránce nebo o kontext uživatelů na pomalém připojení. Zatím to ale, pokud vím, žádný prohlížeč takto nepoužívá.

Téma srcsetsizes je, jak brzy uvidíte, poměrně komplikované, takže je úplně nejlepší se tomu vyhnout. Následující článek by vám měl pomoci s výběrem řešení, ještě než se pustíte do tohoto.

Související: Různé řešení vkládání obrázků na responzivních webech

Ale zpět k našemu tématu. Na atributech srcsetsizes je hezké, že poměrně složité rozhodování, který obrázek ve které situaci použít, necháváme na prohlížeči.

Jako autoři stránky mu jen řekneme, jaké varianty obrázku má k dispozici (srcset) a jak jsou veliké na jednotlivých breakpointech layoutu (sizes).

srcset: Sada zdrojů obrázku a jejich vlastností

<img src="medium_1024.png"
  srcset="
    small_600.png 600w, 
    medium_1024.png 1024w, 
    large_1600.png 1600w"
  width="200" height="200" alt="…">

Prohlížeči tímhle kódem sdělujeme, že jsme předgenerovali obrázek small_600.png. Jeho fyzická šířka (při exportu z grafického editoru) je 600 pixelů, což říká zápis 600w, k němuž se ještě dostaneme. Dále zde máme obrázek medium_1024.png v šířce 1024 pixelů a large_1600.png v šířce 1600 pixelů. V atributu src pak uvádíme náhradní řešení pro prohlížeče, které atribut srcset neumí.

Prohlížeč se zde při rozhodování o tom, který obrázek stáhnout a zobrazit, dívá na aktuální šířku okna.

Některé prohlížeče na to půjdou chytřeji a například small_600.png budou zobrazovat ještě kousek nad hranicí šestisetpixelového okna, protože na vizuální kvalitě obrázku to neubere.

Prohlížeč vezme v potaz i aktuální device-pixel-ratio. Například na zařízení s původním Retina displejem (device-pixel-ratio=2) pak v případě, že okno je široké 600 pixelů, stáhne a použije už největší obrázek, large_1600.png. Potřebuje obrázek velikosti šířky okna krát device-pixel-ratio. Takže kolem 1200 pixelů široký. Obrázek medium_1024.png by mu tedy nestačil.

V potenciálu chytrého rozhodování prohlížeče vězí krása atributu srcset. Prohlížeč zváží všechny informace, které má o stavu stránky k dispozici a podle toho vybere nejvhodnější obrázek. Vy jako autoři jen vygenerujete dost variant a správně je popíšete.

Demo výše uvedeného kódu mám také na CodePenu.

Nejlépe jej vyzkoušíte, když si zmenšíte okno ukázky, obnovíte stránku a pak budete okno postupně zvětšovat.

Kolik variant obrázků vygenerovat?

V ukázce mám obrázky tři, to by ale v praxi nestačilo. Obvykle si vypočtu šířku nejmenší a největší možné varianty. Mezi nimi pak nechám vygenerovat obrázky odstupňované po 200 až 400 pixelech. Je to samozřejmě někdy limitováno i úložným místem na serveru, takže tuto mou radu prosím berte s rezervou.

Deskriptory vlastností obrázků v srcset

Zatím jsem zmínil jen šířku obrázku, tedy deskriptor w. Ten budete používat v naprosté většině případů. Deskriptor x jej doplňuje pro specifické scénáře použití.

deskriptor w

Udává, jakou pixelovou šířku má ve skutečnosti soubor s obrázkem.

<img srcset="
      small_600.png 600w, 
      medium_1024.png 1024w"
    width="200" height="200" alt="…">

Pozor, neříká nic o šířce obrázku v rámci layoutu stránky. K tomu dále slouží atribut width nebo případně CSS.

deskriptor x

Druhý deskriptor určuje připravenost souboru s obrázkem pro různé poměry device-pixel-ratio, například:

<img srcset="
      image.png, 
      [email protected] 2x"
    width="200" height="200" alt="…">

Tímto zápisem říkám, že [email protected] má prohlížeč použít při device-pixel-ratio alespoň 2 a image.png ve všech hodnotách menších než 2. Když deskriptor neuvedete, výchozí je 1x.

Ve skutečnosti je to komplikovanější, protože prohlížeče si logiku za výběrem obrázků řeší samy. Zde například většina vybere obrázek [email protected] už při device-pixel-ratio na hodnotě 1,5.

Pojďme se teď ještě podívat na atribut sizes, který prohlížeči umožní vybírat nejen podle fyzických parametrů souborů s obrázky, ale i podle layoutu vaší stránky.

image-set: Jde to i u obrázku na pozadí

Pokud potřebujete funkcionalitu srcset, ale nikoliv v HTML, ale v CSS, pak je tu zápis image-set():

.box {
  background-image: 
    image-set(
      "obrazek.png" 1x,
      "vetsi-obrazek.png" 2x
    );
}

Od února 2021 to podporuje Firefox (zatím ve verzi Nightly). Díky je možné základní varianty zápisu image-set() používat ve všech moderních prohlížečích.

sizes: Velikost obrázku ve stránce

V praxi totiž tak často nepotřebujeme, aby prohlížeč vybral obrázek podle šířky okna. Spíše podle šířky prostoru pro obrázek v rámci aktuálního layoutu stránky. A právě od toho máme atribut sizes:

<img src="small.png"
  srcset="
    small_600.png 600w, 
    medium_1024.png 1024w, 
    large_1600.png 1600w"  
  sizes="
    (min-width: 768px) 300px, 
    100vw"
  width="200" height="200" alt="…">

Sledujte hodnoty v sizes. Responzivní layout v ukázce je vymyšlený takto:

  • V oknech šířky 768 pixelů a více se obrázek vykresluje do plochy o šířce 300 pixelů ((min-width: 768px) 300px).
  • Ve všech ostatních velikostech okna, tedy do 767 pixelů, zabere 100 procent šířky okna (100vw).

První vyhovující varianta v sizes vyhrává, takže na pořadí záleží. Pozor na to.

Proč si informaci o layoutu stránky prohlížeč nevezme z CSS?

Dobrá otázka. Rozhodnutí, který z obrázků stáhnout a zobrazit, prohlížeče dělají ještě předtím, než znají CSS. Ony v tu chvíli jen rychle parsují HTML a o stylech zatím „nevědí“. Když by na styly čekaly, zpozdí se stažení a zobrazení obrázků. Je to takhle výhodnější pro uživatele. Zkracuje to načtení obrázků a vlastně celé stránky.

Velikosti obrázků podle layoutu

V responzivním layoutu obvykle přesně nevíme, jaké rozměry budou mít obrázky v rámci konkrétní šířky okna. A právě tady se projeví síla kombinace sizes s CSS funkcí calc(). Definovat velikost obrázku můžeme relativně k layoutu mezi konkrétními breakpointy.

Pojďme si nejprve vizuálně přiblížit layout pro další ukázku:

Do 800px breakpointu je to jednoduché: Obrázek zabírá celou šířku layoutu. Nikoliv ovšem šířku okna, a tak musíme odečíst výchozí margin<body>, který mají prohlížeče nastavený na 8px:

calc(100vw - 2 * 8px)

Od breakpointu 800px pak musíme vyjít z CSS layoutu, který je zapsaný takto:

@media only screen and (min-width: 800px) {
  .image {
    width: 49%;
  }
}

Přepsáno do funkce calc() to vypadá takto:

calc((100vw - 2 * 8px) * 0.49)

Ještě v jazyce našeho kmene:

(100 procent šířky viewportu - výchozí margin u <body>) 
  * 49% šířka obrázku

Takže celý zápis tagu <img> bude vypadat takto:

<img src="small_600.png"
  srcset="
    small_600.png 600w,
    medium_1024.png 1024w,
    large_1600.png 1600w"
  sizes="
    (min-width: 800px) calc((100vw - 2*8px) * 0.49),
    calc(100vw - 2*8px)"
  width="200" height="200" alt="…"  >

Pojďme si pro jistotu ještě shrnout celý zápis:

  1. V src máme obrázek sloužící jako náhradní řešení pro starší prohlížeče.
  2. V srcset máme seznam variant obrázku, které jsme předpřipravili a uložili na server.
  3. Atribut sizes říká: na šířkách okna od 800 pixelů výše bude mít obrázek velikost calc((100vw - 2 * 8px) * 0.49). Ve všech ostatních případech – to znamená do 799 pixelů – pak calc(100vw - 2 * 8px).

Nezapomínejte prosím na povinný atribut alt, který ocení vyhledávače a odečítače obrazovky pro zrakově hendikepované uživatele.

Doplňte i atribut height, který vylepší vykreslování stránky tím, že ještě před stažením obrázku sdělí prohlížeči, jak velký prostor pro něj má v layoutu vynechat. Nevztahujte jej tedy k pixelové výšce obrázku, ale k prostoru stránky, který si přejete pro obrázek rezervovat do chvíle, než se stáhne a zobrazí.

„Hernajs, a proč je to tak složité?“

Nedivím se samozřejmě žádným námitkám vůči estetice a zdánlivě zbytečné složitosti autorské práce s responzivními obrázky. Moje první reakce byly stejné. Když si ale zopakujeme, že informace z CSS prohlížeči v momentě parsování HTML nijak nepomohou, asi bychom došli k řešení stejnému nebo velmi podobnému. Pokud bychom jej tedy chtěli vymýšlet znovu, což nikomu nedoporučuji.

V textu o responzivních obrázcích zmiňuji i další alternativy.

Podívejte se také na další možnosti jak zvládnout obrázky v responzivním designu: Kompletní průvodce obrázky v responzivním designu.