(Snad už) Definitivní responzivní obrázky – srcset a sizes

Před rokem tady Robin Pokorný psal o aktuálním vývoji na poli responzivních obrázků, ukazoval src-N variantu řešení a vyjádřil naději, že se standardizátoři již brzy domluví a hlavně — že přijdou nějaké implementace v prohlížečích.
Nálepky:
Pokud jste se také na nějaké řešení těšili a pokud vám doma zbyl po silvestrovských oslavách nějaký sekt, tohle je myslím ta pravá chvíle pro odšpuntování. Máte tu totiž standard, jehož podporu deklarovali všichni významní výrobci prohlížečů a který je s drobným přimhouřením očí s pomocí polyfillu použitelný už dnes.
V responzivním designu často potřebujeme volit mezi různými variantami jednoho obsahového obrázku. Nejčastěji proto, že chceme ušetřit datový objem stránky na mobilech.
Naš starý známý <img>
k tomu nestačí. A tak iniciativa Responsive Images Community Group přišla s novými atributy – srcset
a sizes
– a také s úplně novým tagem <picture>
.
Bavíme se tady o bitmapových obrázcích, typicky fotografiích. Pro ikony, logotypy a další vektorový obsah je lepší použít formát SVG nebo alternativu v podobě ikonfontů.
Proč ne <img src=““>?
Občas je pro responzivní obrázky možné vidět řešení s nahrazováním atributu src:
<img src="large.jpg" data-small="small.jpg" …>
JavaScriptem pak na malých displejích zkopírujete obsah data-small
do src
a prohlížeč zobrazí správný obrázek. Na pohled elegantní, jenže ve výsledku na pytel.
Neexistuje totiž způsob, jak prohlížeč odradit od stažení obrázku nalinkovaného v <img src>
. Proto se v těchto řešeních obrázek sice vymění, ale stáhnou se oba soubory, což na pomalé mobilní síti moc nepotěší.
Proč vlastně více variant obrázků?
Holky a kluci v RICG si sedli a vymysleli 9 scénářů, kdy je potřeba jeden obrázek reprezentovat různými variantami. My si tady ale budeme povídat jen o těch nejdůležitějších:
- Výběr varianty obrázku podle velikosti okna prohlížeče.
- Výběr varianty podle velikosti obrázku v rámci layoutu stránky. V některých situacích totiž můžeme na větším displeji potřebovat menší obrázky. Srovnejte layout pro mobil a tablet na obrázku.
- Výběr podle device-pixel-ratio neboli poměru mezi hardwarovým a CSS rozlišením.
- Výběr podle art direction, jinak řečeno výtvarné řežie. Typicky když obrázek na mobilu potřebujeme oříznout jinak než na desktopu.
S bodem 4 vám pomůže jen nový tag <picture>
, tomu se budeme věnovat v příštím článku. Ve všech ostatních situacích si vystačíte s novými atributy <img>
– srcset
a sizes
. No a o těch si tu budeme dneska vyprávět.
srcset/sizes
Nové atributy elementu <img>
, které řeší potřebu autorů stránek zobrazovat v různých stavech responzivního designu různé varianty obrázků.
Na atributech srcset
a sizes
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é mezi jednotlivými breakpointy layoutu (sizes
).
srcset – sada zdrojů obrázku a jejich vlastností
<img src="small.png"
srcset="small.png 600w, medium.png 1024w, large.png 1600w"
alt="Obrázek" width="200" height="200">
srcset demo na CodePen. (V demu jsme použili polyfill Picturefill, takže funguje ve všech prohlížečích, ale možná jste si všimli nepřítomnosti atributu src.)
Prohlížeči tím sdělujeme, že jsme předgenerovali obrázek small.png
v šířce 600 pixelů, medium.png
v šířce 1024 pixelů a a large.png v šířce 1600 pixelů. V atributu src
pak uvádíme fallback pro prohlížeče, které srcset
neumí.
Prohlížeč pro rozhodování o tom, který obrázek načíst, zde bere šířku okna. Takže do 600 pixelů a méně širokého okna načte small.jpg
, mezi 601 a 1024 pixelů širokým pak medium.jpg
a v oknech šířky od 1025 pixelů načte large.png
.
Některé prohlížeče – jako Chrome – to budou dělat chytřeji a například small.jpg
budou zobrazovat i daleko nad hranicí 600pixelového okna, protože na vizuální kvalitě to obrázku neubere.
Prohlížeč bere v potaz i aktuální device-pixel-ratio, a tak třeba na původním Retina displeji (device-pixel-ratio=2
) načte medium.jpg
i v případě, že okno je široké 600 pixelů. Chrome například načítá kvalitnější obrázek i ve chvíli, kdy uživatel nad obrázkem zoomuje. Do budoucna prohlížeče mohou načítat třeba méně kvalitní obrázek na pomalém internetovém připojení.
Ano, přesně v potenciálu chytrého rozhodování prohlížeče vězí krása 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 – pomocí deskriptorů.
Deskriptory vlastností obrázků v srcset
Zatím jsme zmínili jen šířku obrázku – deskriptor w. Ten říká jakou šířku v pixelech obrázek má při exportu z grafického editoru nebo po výstupu z vašeho skriptu.
Druhý deskriptor x určuje připravenost souboru s obrázkem pro různé device-pixel-ratio
poměry, například:
<img … srcset="image.jpg, image@2x.jpg 2x">
Tímto zápisem říkám, že image@2x.jpg
má prohlížeč použít při device-pixel-ratio
alespoň 2 a image.jpg
ve všech hodnotách menších než 2.
Pojďme se ale podívat na atribut, který prohlížeči umožní vybírat nejen podle fyzických parametrů souborů s obrázky, ale i podle velikosti obrázku v rámci layoutu stránky — sizes.
sizes
– velikosti obrázků
V praxi totiž tak často nepotřebujeme volit obrázek podle šířky okna, ale podle šířky obrázku v rámci layoutu:
<img src="small.png"
srcset="small.png 600w, medium.png 1024w, large.png 1600w"
sizes="(min-width: 768px) 300px, 100vw"
alt="Obrázek" width="200" height="200">
Tímto zápisem říkáme, že responzivní layout je vymyšlený tak, že v rozlišeních nad 768 pixelů má obrázek šířku 300 pixelů ve všech ostatních pak 100 procent šířky viewportu.
První vyhovující varianta v sizes
vyhrává, takže na pořadí záleží. Bacha na to.
Nojo, jenže v responzivním, potažmo fluidním layoutu obvykle přesně nevíme, jaké rozměry budou mít obrázky v rámci konkrétní šířky okna. A hurá — tady přichází síla kombinace sizes
s funkcí calc(). Pomocí ní můžeme elegantně definovat velikost obrázku relativně k layoutu mezi konkrétními breakpointy.
Opět tedy máme demo na CodePenu. Nejdříve si ale raději pojďme vizualizovat, jak vlastně náš layout vypadá:
Do 600px
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
u <body>
, který mají prohlížeče nastavený na 8px
:
calc(100vw - 2*8px)
Od 600px
breakpointu pak musíme vyjít z CSS layoutu:
@media only screen and (min-width: 600px) {
.image {
width: 49%;
}
}
Přepsáno do funkce calc()
to vypadá takto:
calc((100vw - 2 * 8px) * 0.49)
A ještě v prostém jazyce:
(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: 600px) calc((100vw - 2*8px) * 0.49), calc(100vw - 2*8px)"
alt="Obrázek" width="200" height="200">
Pojďme si pro jistotu ještě shrnout zápis v sizes
:
- na rozlišeních od 600 pixelů bude mít obrázek velikost
calc((100vw - 2 * 8px) * 0.49)
- ve všech ostatních případech – to znamená do 599 pixelů – pak
calc(100vw - 2 * 8px)
srcset & sizes demo na CodePenu. (V demu jsme použili polyfill Picturefill, takže funguje ve všech prohlížečích, ale možná jste si všimli nepřítomnosti atributu src.)
Se srcset
a sizes
si vystačíte v naprosté většině situací, kdy budete potřebovat sáhnout po řešení responzivních obrázků.
Pokud budete potřebovat servírovat zcela jinak vypadající obrázky pro různá rozlišení (scénář art direction) nebo obrázky v různých souborových formátech, sáhněte po novém tagu<picture>.
Pomocník pro prohlížeč, ne příkaz
Dobré vědět, že srcset
, sizes
i všechny konstrukce v <picture>
jsou jen jakousi nádstavbou nad stále funkční a povinný mechanizmus <img src>
. Co uzná prohlížeč za lepší alternativu obrázku v <img src>
, tam prostě zkopíruje a zobrazí.
Nevýhody současného řešení
Materiál je to čerstvý, ostatně podpora prvních prohlížečů přišla snad v rekordně krátkém čase po vydání finální verze specifikace. Dále se o něm diskutuje. Proto se nelze divit některým nedořešenostem. Kromě problémů polyfillu je tu například často zmiňovaný fakt, že HTML každého obrázku v sobě nese informaci o nastavení designu. Když se změní, musí chudák vývojář všechny výskyty této informace měnit. Věřím ale, že se tuhle drobnou nevýhodu podaří brzy odstranit. Například přidáním meta tagu, který by informace o layoutu sdružoval na jedno místo.
Podpora v prohlížečích
Prakticky všechny prohlížeče ústy svých tvůrců deklarovaly, že tento standard naimplementují. Ano, včetně Internet Exploreru, ptáte se správně. Jenže jim bude chvíli trvat než to udělají. Nativní podpora je k dispozici v posledních verzích Chrome, Opeře a zčásti Safari. Do té doby – a samozřejmě kvůli starším prohlížečům – je potřeba používat polyfill Picturefill. Ten má jistá omezení, ale ve většině případů vám pomůže s výběrem správné varianty obrázku už nyní, takže se zkoušením není potřeba váhat.
Původně vyšlo na VzhůruDolů.cz. Responzivní obrázky autor také školí na kurzu responzivního designu. Za cenné podněty k materiálu o responzivních obrázcích autor děkuje Robinovi Pokornému, na jehož webu najdete odkazy na přednášky o tomhle tématu.
Je špatné se vypořádat s javascriptovým nahrazení „src“ tak, že uvedu nesmyslný příklad a pak ho sám vyvrátím jako nesmyslný.
V praxi se samozřejmě do „src“ dá ten nejhnusnější a nejmenší obrázek a na lepších zařízeních se nahradí za lepší. Zadarmo tak získáme i rychlé preview. Ne naopak!
Co píšete myslím tu informaci článku doplňuje (za to díky), ale nevyvrací.
V případě použití vašim způsobem se nevýhody zmenšují, ale zůstávají – pořád na některých displejích stahuji zbytečně 2 obrázky namísto jednoho. Datový objem a počet requestů to navyšuje.
Ale abych byl korektní vůči ostatním čtenářům, když už jste to nakousl – jsou situace kdy to řešení může být použitelné. Např. pokud mám ve stránce jeden obrázek, do scr vložím jeho velmi malou variantu a je neefektivní zde nasazovat srcset/sizes.
Mne osobne tedy http://codepen.io/machal/pen/azBmaX?editors=110 ve Firefoxu 34.0.5 funguje. Takze je (alespon castecna) podpora i v nem?
Funguje to defaultne, na dom.image.srcset.enabled jsem nesahal.
Platforma Windows 7 64b.
V příkladech na Codepenu radostně polyfilluji Picturefillem: http://www.vzhurudolu.cz/prirucka/picturefill :-)
Opravdu to tedy funguje téměř všude.
Do příkladů jsem to raději připsal, díky.
Ahoj Martine,
díky za článek, docela mi teď padl vhod, tento týden to přesně řeším. Prosím tě, mám dotaz: máš nějaké zkušenosti s použitím responzivních obrázků a lazy load? Na projektu máme teď unveil.js (myslím, že ho na svém webu také doporučuješ), a chtěla bych tam přidat ješte více variant obrázků. Četla jsem, že samotný unveil má podporu pro retina displaye, ale co v případě mobilů? Nemáš nějaký tip?
Díky moc
Jana
srcset/sizes
a lazyloading jsem zatím nikde nekombinoval. Ale lazyloading beru ve většinu scénářů jako hack pro rychlost načítání na mobilech v době, kdysrcset/sizes
neexistovaly.Výjimku tvoří jen scénáře kdy do stránky načítáš vysoké desítky nebo stovky obrázků nebo situace kdy ty obrázky jsou ohromných velikostí, viz třeba demo na webu Unveil.js. Tam bych o lazyloadingu obrázků dál uvažoval.
Ahoj, díky za odpověď. Nakonec to u nás přesně tak dopadlo a lazy-load jsme vyřadili. Docela ho teď nenávidím :) protože jsme na webu měli spousty různých obrázků a naráželi jsem na špatné počítání výšky webu (pohyb po anchorech na stránce). Uznávám však, že má svoje místo třeba na stránkách, které generují opakující se obsah. Cpát ho úpně všude opravdu nemá cenu. :)