SVG s fallbackem na PNG

Pro responzivní stránky je nejlepší použít vektorové obrázky SVG. Stále ale ještě existují prohlížeče, které ho nepodporují a tak je potřeba zajistit, aby se zobrazilo alespoň PNG (i když ve špatné kvalitě).

SVG v HTML

Pro vložení SVG v HTML můžete použít přímo tag SVG, který díky svému zápisu automaticky vytvoří fallback (zpětnou kompatibilitu) pro zobrazení PNG obrázku:

<svg width="64px" height="64px">
   <image 
    xlink:href="image.svg"
    src="image.png"
    width="100%" height="100%" />
</svg>

Prohlížeč, který zná SVG formát (který se skládá z dvojice tagů SVG-IMAGE nebo SVG-USE), použije definici z xlink:href a stáhne vektorový obrázek. Starší prohlížeče tag SVG ani odkaz xlink nepochopí a tak stáhnou obrázek z atributu src (tag image pochopí jako alias pro používanější img). Některé starší verze IE s experimentální podporou SVG mohou stáhnout oba obrázky (SVG i PNG), což je ale daň za to, že uživatel používá starý prohlížeč.

U této metody je potřeba pamatovat, že DOM struktura bude obsahovat dva vnořené elementy (SVG a IMAGE). Musíte tedy správně přizpůsobit CSS a JS definice (XPATH).

Pro kompatibilitu se všemi prohlížeči (ano, správně se domníváte, že tím myslím IE) je potřeba zadat obrázku (myšleno SVG i IMAGE) nějaké rozměry, aby prohlížeče věděly, jak správně vykreslit (vypočítat) vektorovou grafiku. Rozměry vnitřního obrázku mohou být 100%, aby byl stejně velký jako jeho rodič. Tomu pak nastavte rozměr podle situace – buď procentuálně nebo absolutně. Požadovanou skutečnou velikost samozřejmě můžete určit v CSS (protože CSS má vyšší prioritu než atributy width a height). Nejlepší je tak v HTML nastavit rozměr třeba 64x64px a v CSS pak zadat skutečné rozměry (např. v EM jednotkách).

Zjednodušení přes srcset

Vlastnost srcset je nový atribut v HTML5, který umožňuje stahovat různé obrázky podle rozlišení obrazovky. Využít se dá i pro načtení SVG:

<img src="image.png" srcset="image.svg" />

Nový prohlížeč (Edge, Firefox, Chrome, atd.) zná atribut srcset a proto stáhne vektorový soubor. Naopak staré prohlížeče (momentálně všechny IE a staré mobily) srcset neznají a tak stáhnou PNG tak jako u obyčejného obrázku.

Tento přístup je lepší než předchozí ze dvou důvodů: 1) nezmění se DOM struktura, protože bude stále obsahovat pouze daný obrázek (v porovnání s dvojicí SVG-IMAGE v předchozím případě) a 2) vyřeší se problém s IE, které nesprávně SVG zobrazuje (protože ho vůbec nenačte). Nevýhodou je pak to, že pomocí srcset pokryjete mnohem menší procento prohlížečů (celosvětově 96% vs. 68% na počátku 2016), než kolik jich skutečně SVG podporuje (protože SVG podporují všechny prohlížeče od IE9+ a iOS4+, zatímco srcset podporují jen moderní Edge a iOS9+; Chromium a Firefox samozřejmě nepočítám a u Android je to 4.4 vs. 5+ takže celkem minimální rozdíl).

Nicméně pokud potřebujete do stávajících stránek rychle doplnit podporu responzivních obrázků a pokrýt alespoň uživatele s nejnovějšími prohlížeči, můžete použít tento „trik“ místo pracného nahrazování img za svg-image.

Chyby v IE a iOS8

V Internet Exploreru se na SVG aplikuje stejná chyba jako u ostatních obrázků, která spočívá v tom, že neumí správně spočítat výšku, pokud je zadána jako automatická (height: auto;). Pak musíte použít JavaScript a výšku SVG nastavit při každé změně velikosti stránky:

if (-1 < navigator.userAgent.indexOf('MSIE') 
 || -1 < navigator.userAgent.indexOf('Trident/')
 || -1 < navigator.userAgent.indexOf('Edge/')
) {
    $(window).on('resize.svg-dize', 
        function() {
            $('svg').each(function() {
                var me = $(this); 
                //pro čtvercové SVG:
                me.height(me.width());
            });
         });
    $(function() {
        $(window).triggerHandler(
            'resize.svg-size'); 
    });
}

Na iPhone a iPad (iOS8 a starších) se provádí vykreslování SVG trochu nestandardně (a dalo by se říci i chybně). Safari (resp. WebView poháněné webkitem) totiž správně aplikuje rozměry zadané v CSS na vnější SVG element, ale vnitřní IMAGE element vyrenderuje ve velikosti podle zadaných HTML atributů width a height, přičemž zcela ignoruje skutečnou velikost elementu. Proto je potřeba velikost spočtenou z CSS uložit i do HTML atributů:

if (navigator.userAgent.match(
    /(iPhone|iPad|iPod)\ OS\ [1-8]_/)) {
    $(window).on('resize.svg-size', 
        function() {
            $('svg').each(function() {
                var me = $(this);
                me.attr('width', me.width());
                me.attr('height', me.height());
            });
    });
    $(function() {
        $(window).triggerHandler(
            'resize.svg-size');
    });
}

SVG v CSS

Pro použití SVG jako obrázku na pozadí můžete využít toho, že vlastnost background-image u novějších prohlížečů (které SVG podporují) umožňuje zadat více obrázků oddělených čárkou, přičemž jedna z validních hodnot je none.

Oproti tomu všechny prohlížeče, které nepodporují SVG, taktéž nepochopí, když do background-image uvedete none a tak budou danou definici ignorovat:

el {
    background-image: url(image.png);
    background-image: none, url(image.svg);
}

Druhý řádek v nové prohlížeči přepíše ten první, takže se bude stahovat jen SVG. Staré prohlížeče ale budou druhý řádek považovat za nevalidní, budou ho ignorovat a proto se stáhne PNG.

Alternativně lze místo hodnoty none použít definici barvy přes rgba() funkci, která není taktéž podporována na starých prohlížečích. Pozor ale na to, že v tomto případě musíte místo background-image použít celé background a znovu nadefinovat všechny vlastnosti:

el {
    background: transparent url(image.png) repeat center center;
    background: rgba(0,0,0,0) url(image.svg) repeat center center;
}

Ještě lepší metoda, která odstraňuje problém s některými starými telefony (konkrétně Android 2.x), je místo hodnoty none použít gradient, který na starých prohlížečích není podporován (a na nových nic nezmění, protože bude průhledný). Problém je, že aby fungoval na webkitu, musíte uvést ještě prefixovanou verzi:

el {
    background-image: url(image.png);
    background-image: -webkit-linear-gradient(transparent, transparent), url(image.svg);
    background-image: linear-gradient(transparent, transparent), url(image.svg);
}

SVG v HTML5

V HTML5 také existuje element PICTURE, který umožňuje zadat obrázek v různých formátech. Více viz Responzivní načítání obrázků.

<picture>
   <source type="image/svg+xml" src="picture.svg">
   <img src="picture.png">
</picture>

Optimalizace PNG

Pro vytvoření co nejmenšího PNG se podívejte na článek Úprava obrázků pro web.

Komprese SVG

Jelikož jsou SVG soubory interně uloženy jako XML, jde tedy o text a je možno je poměrně dobře komprimovat. Na webu se často používá komprese gzip, kterou podporuje většina prohlížečů.

Pokud váš server běží na Apache, můžete nechat SVG automaticky komprimovat tak, že do složky, kde jsou obrázky uloženy (např. /public/images/), přidáte soubor .htaccess a do něj vložíte:

# compress SVG images
<IfModule mod_filter.c>
    <ifmodule mod_deflate.c>
        AddOutputFilterByType DEFLATE image/svg+xml
    </ifmodule>
</ifmodule>

V konfiguraci Apache (https.conf) pak najděte následující řádky a smažte „#“ na jejich začátku (pokud tam je):

LoadModule filter_module modules/mod_filter.so
LoadModule deflate_module modules/mod_deflate.so

Pokud máte jiný server (IIS, nginx, apod.) může být konfigurace jiná.

Tip: ve Windows průzkumníku nelze vytvořit začínající tečkou, ale lze ho vytvořit v konzoly. Ve Windows 10 stačí najít složku v průzkumníku, zvolit Soubor > Otevřít příkazový řádek a zadat:

copy nul .htaccess

Dopředu zabalené SVG

Alternativně, pokud komprese při každém requestu není vhodná nebo použitelná, existuje speciální formát pro komprimované SVG. Můžete ručně zabalit SVG pomocí gzip a uložit s příponou *.SVGZ.

Na Windows můžete pro kompresi použít program 7zip (nezapomeňte zvolit metodu gzip místo 7zip!), na linuxu si vystačíte s příkazem:

gzip -c logo.svg > logo.svgz

#pokud neni gzip nainstalovan:
yum install gzip
#nebo
apt-get install gzip

Poté, co získáte komprimovaný obrázek, je potřeba nastavit server tak, aby místo SVG souborů odesílal SVGZ těm prohlížečům, které podporují gzip kompresy (což se pozná podle HTTP hlavičky). Příklad podle dokumentace k Apache mod_deflate:

 #Musíte zapnout mod_headers.so v Apache
<IfModule mod_headers.c>
    #pokud prohlížeč podporuje gzip
    RewriteCond "%{HTTP:Accept-encoding}" "gzip"
    #a chce stáhnout svg soubor
    RewriteCond "%{REQUEST_FILENAME}\.svg" -s
    #pošli mu místo něj svgz
    RewriteRule "^(.*)\.svg" "$1\.svgz" [QSA]
    #nastav správný MIME type (a vypni deflate module)
    RewriteRule "\.svgz$" "-" [T=image/svg+xml,E=no-gzip:1]
    #a pošli hlavičky informující o kompresi obsahu
    <FilesMatch "\.svgz$">
      Header append Content-Encoding gzip
      Header append Vary Accept-Encoding
    </FilesMatch>
</IfModule>

 

Napsat komentář

Vaše emailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *