Často se u responzivních webů setkáte s následujícím CSS:
img { max-width: 100%; height: auto; }
Toto pravidlo zajistí, že se obrázky na stránce přizpůsobí šířce rodičovského elementu, ale nepřekročí svou skutečnou šířku. Zároveň si udrží správný poměr stran.
Problémy nastávají v momentě, kdy chceme obrázek roztáhnout nad jeho skutečnou velikost. Pokud jde o vektorový obrázek, všechno je v pořádku, ale bitmapy začnou velmi rychle ztrácet na kvalitě. Teoreticky můžeme obrázek nahrát ve vyšším rozlišení a na menších displejích ho prostě zmenšit. Tak už by sice vypadal dobře, akorát že uživatelé na mobilu teď musí stáhnou obrázek ve 4K, aby se jim ve finále zobrazil v šířce pouze 380 pixelů.
Co je pro řešení takové situace potřeba, jsou různé velikosti obrázku pro různá rozlišení. A právě to řeší atribut srcset.
Srcset
Pomocí srcset je možné definovat sadu obrázku a jejich reálné velikosti. Ze sady si pak prohlížeč vybere právě tu velikost, kterou potřebuje:
<!-- Sada různých velikostí obr. pro různé šířky okna --> <img srcset="small_320.jpg 320w, medium_768.jpg 768w, large_1280.jpg 1280w" src="large_1280.jpg" alt="..." />
V sadě je vždy zapsána cesta k obrázku nějaké velikosti a následuje jeho šířka. Ta je sice uvedená v pixelech, ale popsána je deskriptorem w (aby bylo jasné, že jde o šířku). Uvedená šířka má odpovídat skutečné velikosti obrázku v souboru a ne šířce obrázku ve stránce - ta je definována v CSS nebo atributem width. Atribut src slouží pouze jako fallback prohlížečům, které srcset neumí.
Proč se uvádí šířka, ale už ne výška? V praxi se většinou omezuje pomocí CSS pouze šířka obrázků a výška zůstává automatická, aby byl zachován správný poměr stran. Specifikace srcset se proto snaží zachovat jednoduchost a definuje pouze šířku (alespoň zatím).
Prohlížeč si správnou velikost vybírá už při přednačítání obrázků, takže dávno předtím, než začne vůbec skládat DOM nebo zpracovávat CSS. Tím šetří čas a hlavně načítá ze srcset pouze ty obrázky, které bude používat.
Jak se vybere správná velikost?
Sice při výběru nemá prohlížeč k dispozici informace z CSS, ale v tu chvíli už zná například šířku okna a poměr hardwarových a logických pixelů (device-pixel-ratio). Na základě toho udělá pro výběr správného obrázku jednoduchý výpočet:
Řekněme, že šířka okna je 580 pixelů a v srcset jsou definovány velikosti z příkladu výše: 320w, 768w a 1280w.
320 (velikost 1. obrázku) / 580 (šířka okna) = 0,55 768 (velikost 2. obrázku) / 580 (šířka okna) = 1,32 1280 (velikost 3. obrázku) / 580 (šířka okna) = 2,2
Z výsledků pak vybere hodnotu nejbližší 1. Hodnoty < 1 ignoruje. V tomto případě by vybral 2. obrázek (medium_768.jpg).
Zařízení s vyšším device-pixel-ratio
Pokud bychom chtěli definovat sadu obrázků pro zařízení s vyšším poměrem hardwarových a logických pixelů (např. Retina displeje), použijeme deskriptor x:
<!-- Sada různých velikostí pro různou device-pixel-ratio --> <img srcset="image.jpg, image_2x.jpg 2x" src="image_2x.jpg" alt="..." />
Na těchto zařízeních se pak vybere obrázek s vyšším rozlišením. Toto ale funguje automaticky i při použití deskriptoru w. Při výpočtu správné velikosti by se pouze násobila šířka okna s device-pixel-ratio. Například zařízení s šířkou okna 768 px a device-pixel-ratio 2 by mělo logickou šířku 1536 pixelů.
Sizes
Podle layoutu mohou být obrázky široké třeba jen čtvrtinu šířky okna. Potom je zbytečné, aby se stahovaly mnohem větší velikosti. Samotný srcset ale neví, jaký layout stránka má. Zajímá ho pouze celé okno. Proto tady je atribut sizes.
Pomocí sizes lze definovat sadu podmínek (např. šířku okna) a říct kolik bude obrázek ve stránce zabírat místa, pokud bude určitá podmínka platit.
<!-- Sada podmínek pro zobrazení určitých velikostí --> <img srcset="small_320.jpg 320w, medium_768.jpg 768w, large_1280.jpg 1280w" sizes="(min-width: 900px) 33vw, (min-width: 400px) 400px, 100vw" src="large_1280.jpg" alt="..." />
Zapisuje se jako sada čárkou oddělených dvojicí podmínka a velikost. Podmínky mají stejný způsob zápisu a možnosti jako media queries v CSS. I velikost používá klasické CSS jednotky. Pozor, neumí procenta. Místo nich používá poměr vw (viewport width). Velikost bez podmínky se bere jako výchozí a aplikuje se, pokud žádná podmínka nevyhovuje.
Po první platné podmínce se ty ostatní přeskakují. Takže pozor na pořadí!
Příklad výše říká, že:
- Do šířky okna 399 px obrázek zabírá na stránce 100vw (celou šířku)
- Mezi 400 - 899 px šířkou je obrázek široký 400 px
- Od šířky 900 px nahoru je obrázek široký 33vw
Tyto definice bere prohlížeč v potaz a podle nich vybere ze sady srcset nejvhodnější velikost.
Pro příklad, máme okno široké 680 pixelů. Podle pravidel v sizes by měl být obrázek ve stránce široký 400 px. Ze srcset se pak vybere obrázek medium_768.jpg široký 768 px.
Podpora
U moderních prohlížečů je podpora srcset i sizes vcelku dobrá - https://caniuse.com/#search=srcset. IE 11 a starší Android je bohužel nezvládnou, ale díky atributu src je alespoň zajištěný fallback a tak doporučuji obojí používat, kde to jde. Ušetříte datový objem stránky a možná i nervy s laděním.
Navíc, některé CMS systémy (např. Wordpress) mají zabudováno automatické generování těchto atributů v základu. Ale o tom třeba příště.
Řešíte responzivitu obrázků? Používáte jiný přístup? Dejte nám v komentářích vědět jaký!
K tomuto článku již není možné přidávat další komentáře
Komentáře
Hezký článek, ale doplnil bych použití tagu picture, kdy si já sám rozhodnu co v jakém BP naservíruji a nenechám za sebe rozhodovat prohlížeč.
Ahoj, srcset a sizes se hodí pro případy, kdy už by bylo použití picture tagu s pravidly v media atributu nepřehledné. V tomto článku je pěkný příklad: https://ericportis.com/posts/2014/srcset-sizes/#study-up .
Atribut sizes se jeví vcelku jasně, ale ...
Např. když používám bootstrap 4 a obrázek mi zabírá dejme tomu šířku col-md-3 (což je reálně 25%), jakou šířku v sizes nastavím? 25% / 25vw nebo co? Pixelovou logicky nemůžu.
Navíc žiji v dommění že jednotka vw se vztahuje k šířce celého okna, takže ani 25vw nedává zcela smysl.
Díky za objasnění.
Ahoj, procenta bohužel sizes neumí, protože ta závisí na CSS, které prohlížeč při parsování HTML ještě nemusí znát.
Umí ale počítat přes funkci calc() a třeba Martin Michálek píše, jak to aplikovat na podobný případ, který popisuješ: https://www.vzhurudolu.cz/prirucka/srcset-sizes#velikos...-layoutu .
Osobně jdu u jednodušších případů jednou ze dvou možností. Buď si přepočítám velikost z procent relativně k viewportu, tedy spočítám si jak velkou část viewportu mi zabírá, nebo si stanovím nějakou maximální velikost v px. Např. vím že mezi viewportem 800 - 1200 px budou obrázky ve třech sloupcích a můžou být maximálně 300px široké, nastavím pro tento breakpoint velikost 300px.
Díky za info :-)
PS. nechodí notifikace na e-mail (u starého blogu chodily).