How to add a CSS class to images that didn’t load?

Asked

Viewed 4,043 times

20

I have an HTML page with numerous images presented as follows:

<img alt="img1" width="50" height="120" src="my_image.jpg" />
<img alt="img2" width="50" height="120" src="another_image.jpg" />
<img alt="img3" width="50" height="120" src="yet_another_image.jpg" />

If any of the images do not load due to reason A or B, there will be breaks in the layout or some browsers, the image square will appear with the alternate text, making the whole look a little ugly.

Question

How can I via jQuery add a CSS class to images whose load action failed ?

Example:

<img alt="img1" width="50" height="120" src="my_image.jpg" class="failToLoad" />
  • If the image is external (e.g. Imgur) with an invalid url the image will not generate error 404, so solutions using the event error may not cover all cases.

3 answers

9


The most "natural" way would be to use the onerror (jQuery: error), but be careful as this event will only be captured if it occurs afterward that the Handler has already been added. Therefore, a solution would be to put the script that adds the class at the beginning of the document (head, or beginning of body - before any img). So it doesn’t get too heavy, a solution without jQuery:

<script type="text/javascript">
function erro(elemento) { 
    elemento.className += ' failToLoad'; // Adiciona a classe às já existentes, se houver
}
</script>
...
<img src="..." onerror="erro(this)" />

Example in jsFiddle.

An alternative way, based in this answer in the English OS, it seems to work correctly if it is necessary to put the Javascript at the end (in onLoad of the document, for example).

$('img').each(function() {
    if (!this.complete || typeof this.naturalWidth == "undefined" || this.naturalWidth == 0) {
        $(this).addClass('failToLoad');
    }
});

Example. The advantage of this technique is that no changes to HTML tags are required.

  • 1

    Note that the jsFiddle example is running in the event onLoad. For this code to work it must be after all elements img or in one of the events: DOMContentLoaded or Load

  • 1

    Alias, testing further I noticed that the second alternative only works in the event load. Because if the images are not cached the property complete will not always be true.

  • 1

    @Brunolm Truth, this also occurred to me when I first saw the code. I imagine that, of the three one: 1) the complete will be ready when the script runs; 2) load image will perform (giving the chance to clear the class); 3) the error image will run. So that the first alternative seems to me more reliable IMHO.

3

You can assign an event to error on the desired images and add the class failToLoad

Example

$("#falha")
.on('error',function(){
   $(this).addClass('failToLoad');
   console.log('Essa imagem nao carregou');
})
.attr('src','falha.png');

Remembering that you cannot recover error after image and DOM are loaded, since the browser will have already propagated the event of error while loading image, so you should enter the src after attaching the event to it.

This difficulty is highlighted in the jQuery API .error()

Jsfiddle example

Solution

An automatic solution would be to use tags data-*

HTML
<img data-src="falha.png">
Javascript
//Para cada <img> da página
$('img').each(function(){
    //Selecionar essa imagem
    $(this)
    //Atribuir o evento de erro
    .on('error', function(){
        //Caso ocorra o erro, adicionar a classe failToLoad
        $(this).addClass('failToLoad');
    })
    //Definir o src da imagem recuperando do atributo data-src
    .attr('src',$(this).data('src'));
});

So, all your images that are wrong to load will automatically win the class failToLoad

Jsfiddle solution

1

For new elements inserted dynamically it is possible to do using the MutationObserver. And for the other images just get them and add the event.

var observer = new MutationObserver(
    function(mutations) 
    {
        for (var m in mutations)
        {
            var mutation = mutations[m];

            if (mutation.addedNodes) // todos nodos adicionados
            {
                for (var i = 0; i < mutation.addedNodes.length; ++i)
                {
                    var node = mutation.addedNodes[i];

                    if (node.nodeName == "IMG") // se for imagem
                    {
                        // adiciona o evento "error"
                        // caso o erro ocorra, a classe será adicionada
                        node.addEventListener("error", function() {
                            node.className += " failToLoad";
                        }, false);
                    }
                }
            }
        }
    }
);

// inicia o observer
observer.observe(document, { childList: true, subtree: true });

And for the elements already existing on the page:

$(function() { // quando a página carregar o DOM

    // para todas imagens da página
    $("img").each(function(i,e) {

        // adiciona o evento
        e.addEventListener("error", function(imgEvents) {
            var img = e;

            e.className += " failToLoad"; // em caso de erro adiciona classe

        }, false);

    });
});

See this example in jsFiddle. Note that dynamically inserted images are also validated. In this example the script is being inserted between the tag <head>.

Note that if the image is external, for example Imgur, and you pass an invalid link the site will not generate error 404 instead it will generate a default image.

imagem de erro do imgur

Browser other questions tagged

You are not signed in. Login or sign up in order to post.