Stylování nenačteného obrázku

Pokud se ve stránce nenačte obrázek, zpravidla to znamená chybu serveru a je potřeba ji opravit. Když je to chyba vašeho serveru, zpravidla to není problém, ale řada stránek načítá obrázky z jiných serverů, např. CDN třetích stran, kde dostupnost nelze moc ovlivnit (a často může být jen dočasná).

Nicméně to návštěvníka nezajímá. Z jeho pohledu stačí, když mu místo nedostupného obrázku zobrazíte něco jiného. HTML k tomuto účelu nabízí atribut ALT, který může (resp. měl by) obsahovat popis toho, co by bylo na obrázku vidět, kdyby se zobrazil. Nicméně obyčejně zobrazený text v základním stylu už dopředu říká „tady něco není v pořádku“ zvláště v okamžiku, kdy máte stránku založenou na speciálním designu.

Námět článku: http://bitsofco.de/styling-broken-images/

CSS pro text

Základní věcí, kterou můžete udělat, je naformátovat alternativní text pomocí CSS. I když se to může zdát nesmyslné, i obrázkům lze nastavit vlastnosti jako je velikost či barva písma. Ty se pak nepoužijí na obrázek, ale na alternativní text:

img {
    font: italic 12px Verdana, sans-serif;
    color: gray;
    text-align: center;
}

Dodané prvky

Další možností, pokud chcete na alternativní text použít více stylů (např. border), je přidat do CSS tzv. dodané prvky – tedy prvky :before nebo :after. Tento způsob sice funguje jen Chrome (+ Opera) a Firefoxu (což je přes 50% lidí), ale dá se pomocí něj mnohem lépe nastylovat chybějící obrázek:

img { position: relative; }

/* doplní text před obrázek */
img:before {
    content: "Tento obrázek chybí:"
    display: block;
}

/* překryje obrázek průhledným overlay */
img:after {
    content: " ";
    position: absolute;
    left: 0; top: 0; right: 0; bottom: 0;
    background: red url('/missing.jpg');
    opacity: 0.5;
}

Dodané prvky fungují díky faktu, že obrázek sám dodané prvky mít nemůže, takže pokud se obrázek načte, definice :before a :after se budou ignorovat. Ale v okamžiku, kdy se obrázek nenačte, změní Webkit a Firefox prvek z obrázku na text, který již tyto prvky mít může.

Pokud chcete původní obrázek zcela překrýt jeho dodaným prvkem, ale chcete, aby obsahoval jeho alternativní text, můžete k tomu použít CSS content funkci:

img { position: relative; }

/* překryje obrázek průhledným overlay */
img:after {
    content: attr(alt); /* zkopíruje alt */
    position: absolute;
    /* zvětší prvek pro kulaté okraje */
    left: -5px; top: -5px;
    right: -5px; bottom: -5px;
    background: red url('/missing.jpg');
    border-width: 0px; /* bez okraje ale ...*/
    border-radius: 5px; /* s kulatými rohy */
}

Safari a IE (vč. Edge) se i k nenačtenému obrázku chovají pořád stejně, což znamená, že i nadále ignorují jeho :before a :after styly. Fakt, že toto funguje ve Webkit a Firefoxu je spíše důsledek chyby nebo nesprávné interpretace HTML specifikace. Použití dodaných prvků se tedy dá přirovnat je starým CSS hackům, které spoléhali na různé chování různých prohlížečů. Také je možné, že se v budoucnu i Webkit nebo Firefox začne chovat jinak.

Javascript

Samozřejmě pokud chcete nastylovat prvek i v Safari a IE, nebo chcete použít styly, které ani Webkit a Firefox nepodporují, můžete použít Javascript a hlídat, zda se obrázek načetl:

$('img').on('error', function() {
    $(this).addClass('missing');
});

Následně pak stačí CSS upravit tak, aby brala v úvahu i tuto třídu:

img { position: relative; }

/* Změní chybějící obrázek na text
   aby :before a :after fungovalo
   i na Safari a IE/Edge */
img.missing { content: ""; }

/* doplní styly jen pro chybějící obrázky */
img.missing {
    margin: 0.5em;
    padding: 0.5em;
    display: block;
}

/* doplní text před obrázek */
img:before {
    content: "Tento obrázek chybí:"
    display: block;
}

/* překryje obrázek průhledným overlay */
img:after {
    content: " ";
    position: absolute;
    left: 0; top: 0; right: 0; bottom: 0;
    background: red url('/missing.jpg');
    opacity: 0.5;
}

Obrázek v pozadí

Stále častější je nedávat obrázek přímo do HTML (formou IMG nebo PICTURE) ale použít CSS a jeho background-image. V takovém případě se již bez javascriptu neobejdete, protože pro CSS není obrázek na pozadí povinný a tak jeho nepřítomnost nic nezpůsobí.

V javascriptu sice také nemůžete přímo zjistit, zda se obrázek na pozadí zobrazil nebo ne, ale můžete si přečíst url požadovaného obrázku, zkusit ho stáhnout a ověřit tak, zda je v prohlížeči dostupný:

function testBgImage(el) {
    //získání jQuery wrapperu
    el = $(el);
    //získání background-image
    var image = el.css('background-image');
    //získání URL z vlastnosti
    image = image.match(
            /url\(["']?(.*?)["']?\)/i
    );
    //pokud jde o url obrázku...
    if (image[1]) {
        //...zkus ho stáhnout
        $.ajax({url:$image,type:'HEAD'})
            //pokud existuje:
            .done(function() { ... })
            //pokud neexistuje
            .fail(function() { ... });
        ;
    }
    //pokud prvek nemá žádný obrázek v pozadí
    else { ... }
}

Uvedený kód má dva hlavní body:

Zaprvé musí správně získat URL obrázku z vlastnosti background-image, protože URL je obalená funkcí url() a navíc v CSS3 může obsahovat více definic (např. pro načtení SVG: „none, linear-gradient(...), url('logo.svg')„) – proto se použije regulární výraz, který najde první url v definici a tu použije. (Poznámka: selektor „.*?“ je tzv. non-greedy a zabraňuje tomu, aby se koncová uvozovka stala součástí url místo aby se počítala jako konec funkce).

Zadruhé se kód pokusí obrázek stáhnout. To se může zdát zbytečné, protože se bude obrázek jednou stahovat pro CSS a podruhé pro JS. Prohlížeč (při správné konfiguraci serveru) ale stáhne obrázek jen pro CSS a v JS použije jen odpověď z cache. Navíc i kdyby cache nezafungovala, nebude se stahovat celý obrázek ale díky HEAD requestu se jen ověří, že obrázek na serveru existuje. To samozřejmě předpokládá, že váš server správně zvládá odpověď na HEAD request (většina běžně používaných serverů by to měla umět) a že v případě neexistence obrázku správně vrátí kód 404 Not Found.

Napsat komentář

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