97

Do you know how to hide the classic “Image not found” icon from a rendered HTML page when an image file is not found?

Any working method using JavaScript/jQuery/CSS?

systempuntoout
  • 71,966
  • 47
  • 171
  • 241
  • I don't see the point. You're just not supposed to try to reach no existing ressources from your html code. Using javascript to hide bad dealed ressources seems to be an ugly solution to me. – Boris Delormas Jul 13 '10 at 10:30
  • 1
    @Kaaviar You are missing the point.There are a lot of hotlinked images broken here on Stack Overflow due to the fact that images can be available at the time of the post, but unavailable some months later. These images are silently and gently hided. – systempuntoout Jul 13 '10 at 10:37
  • @systempuntoout: broken images posted in questions show the broken image icon for me. I just tested it. – Andy E Jul 13 '10 at 10:45
  • Wouldn't it be kind to check serverside whether the images still exists and act the good way in order not to make the client send useless http resquests ? – Boris Delormas Jul 13 '10 at 10:46
  • @Andy uhm..browser? I'm using FF 3.6.3 and broken images are hided. I've tried IE 8.0 and broken image icons are displayed :S – systempuntoout Jul 13 '10 at 10:48
  • @systempuntoout: I tested in IE and Google Chrome. It's possible Firefox hides the images on its own if they have a blank `alt` attribute. btw, do you have a link to the question you checked? – Andy E Jul 13 '10 at 10:55
  • @Andy sure .. http://superuser.com/questions/52671/how-do-i-create-unicode-smilies-like- – systempuntoout Jul 13 '10 at 10:58
  • @Andy the same page using StackPrinter (i'm the author) shows the broken links on FF 3.6.3 . That's the reason why i asked this question :). http://stackprinter.appspot.com/export?question=52671&format=HTML&service=superuser – systempuntoout Jul 13 '10 at 11:02
  • 1
    @systempuntoout: I'm not sure why the two are treated differently. [I tested a broken image](http://jsfiddle.net/aVhc8/) in Firefox and Chrome, it doesn't show in Firefox but it shows as broken in Chrome. It's clear that this is something Firefox is deciding on its own, as it doesn't appear that any styles are affecting it. btw, great work on StackPrinter. – Andy E Jul 13 '10 at 11:11
  • 2
    @systempuntoout: I found out a little more information about how Firefox works with this. See an [updated fiddle](http://jsfiddle.net/aVhc8/1/) and the [proprietary pseudo-class, `:-moz-broken` ](https://developer.mozilla.org/en/CSS/:-moz-broken). I was just thinking to myself earlier that a pseudo class would be useful for styling broken images. – Andy E Jul 13 '10 at 12:02
  • @Andy thanks for the hints and for the +1 over there :). – systempuntoout Jul 13 '10 at 12:25
  • @systempuntoout: no problem at all :-) – Andy E Jul 13 '10 at 12:40
  • Andy's reply is correct, however, you might want to use style.vsibility instead. If you set visibility, the element still keeps its space on your document, thus no funny document movements. – Christian Jul 13 '10 at 09:53

9 Answers9

118
<img onerror='this.style.display = "none"'>
Gary Willoughby
  • 50,926
  • 41
  • 133
  • 199
106

You can use the onerror event in JavaScript to act when an image fails to load:

var img = document.getElementById("myImg");
img.onerror = function () { 
    this.style.display = "none";
}

In jQuery (since you asked):

$("#myImg").error(function () { 
    $(this).hide(); 
});

Or for all images:

$("img").error(function () { 
    $(this).hide();
    // or $(this).css({visibility:"hidden"}); 
});

You should use visibility: hidden instead of .hide() if hiding the images might change the layout. Many sites on the web use a default "no image" image instead, pointing the src attribute to that image when the specified image location is unavailable.

Andy E
  • 338,112
  • 86
  • 474
  • 445
  • 1
    andy - what would be the 'global' solution to apply to ALL images?? i'm thinking it would be easy enough if they were all in the same div - just wondered about ALL images in the document... – jim tollan Jul 13 '10 at 09:55
  • @jAndy: I was fairly sure it is, but your comment made me double-check. A quick Google returned this [w3schools page](http://www.w3schools.com/jsref/event_img_onerror.asp) (sorry David, if you're reading this) indicating cross browser support. – Andy E Jul 13 '10 at 09:56
  • 2
    @jim: If you're using jQuery, you can apply the event to all images. just use the tag selector, e.g. `$("img").error(function () { /*...*/ });`. – Andy E Jul 13 '10 at 09:57
  • @Andy E: sounds good, +1. next interesting question would be, is "`error`" boundable with `live()` or `delegate()`. – jAndy Jul 13 '10 at 09:58
  • StackOverflow engine seems to have a different approach, i've searched your solution on master js but i did not found any .error at all. Do you know how they handle it? – systempuntoout Jul 13 '10 at 09:58
  • Unfortuantly, its not possible to `live` bind the `error` event. – jAndy Jul 13 '10 at 10:07
  • @jAndy: I'm pretty sure you can only use `live()` and `delegate()` for custom events, events that bubble and events that don't bubble but have a bubbling alternative. Check the [ *Caveats* ](http://api.jquery.com/live/#caveats) section of the docs. – Andy E Jul 13 '10 at 10:07
  • 3
    `visibility` would be better, since `display` can break the layout. – gblazex Jul 13 '10 at 10:18
  • @systempuntooout: I'm not sure there is any other way to handle it. There's possibly some clever trick that I'm not aware of. If you want to know how something is implemented in Stack Overflow you could try asking over at http://meta.stackoverflow.com. – Andy E Jul 13 '10 at 10:19
  • @galambalazs: it depends on the usage, but `visibility` would be more useful. Many sites on the web do neither, instead swapping the image for a default, "no image" image. – Andy E Jul 13 '10 at 10:21
  • If you are using ajax anywhere you are going to want to add this to your little hack. `$.ajaxSetup({complete: function() { $("img").error(function () { $(this).css({visibility:"hidden"}); });} });` – Adrian Mar 06 '15 at 20:04
12

I've slightly modified the solution suggested by Gary Willoughby, because it briefly shows the broken image icon. My solution:

    <img src="..." style="display: none" onload="this.style.display=''">

In my solution image is hidden initially and is shown only when it is successfully loaded. It has a disadvantage: users will not see halfloaded images. And if user has disabled JS then they will never see any images

Sash
  • 315
  • 3
  • 6
7

To hide every image error, just add this JavaScript at the bottom of your page (just before the closing body tag):

(function() {
    var allimgs = document.images;
    for (var i = 0; i < allimgs.length; i++) {
        allimgs[i].onerror = function() {
            this.style.visibility = "hidden"; // Other elements aren't affected. 
        }
    }
})();
rvighne
  • 20,755
  • 11
  • 51
  • 73
Q_Mlilo
  • 1,729
  • 4
  • 23
  • 26
  • This is my preferred approach because it pretty much ensures that the onerror events are bound before the images have errored out and you don't have to add onerror attributes to each image tag. Be sure to put this code after all your image tags but before any other javascript that's in , otherwise a blocking external JS load may cause execution after an image error. – galatians Oct 15 '15 at 22:13
  • This one works for me, along with the advice from galatians, need to have this JS execute before anything that might delay it. – Adamz Feb 03 '16 at 23:34
  • This answers the the original question, but it's a one-way process. To make images that subsequently load visible again, add an onload event as well. allimgs[i].onload = function() { this.style.visibility = "visible"; }; – TRT 1968 Oct 19 '19 at 17:01
5

It may be little late to answer, but here is my attempt. When I faced the same issue I fixed it by using a div of the size of image & setting background-image to this div. If the image is not found, the div is rendered transparent, so its all done silently without java-script code.

Adway Lele
  • 394
  • 2
  • 11
4

Doing a quick research on Andy E's answer, its not possible to live() bind error.

// won't work (chrome 5)
$('img').live('error', function(){
     $(this).css('visibility', 'hidden');
});

So you have to go like

$('<img/>', {
  src:    'http://www.notarget.com/fake.jpg',
  error:  function(e){
    $(this).css('visibility', 'hidden');
  }
}).appendTo(document.body);

directly binding the error event handler on creating a new element.

jAndy
  • 231,737
  • 57
  • 305
  • 359
  • 2
    +1, the reason for this is that the *onerror* DOM event doesn't bubble. *live* and *delegate* work by placing the event handler further up the DOM hierarchy and capturing the event as it bubbles up. Of course, the jQuery devs have worked around this for some events like *focus* and *blur* – Andy E Jul 13 '10 at 10:10
  • @Andy E: Yay, they already workedaround that, might be not the worst of ideas to do a similar thing for `error`. Sounds like a `nice to have` for me. – jAndy Jul 13 '10 at 10:18
4

i've found a nifty method to do exactly this, while being still functional when using ng-src directive in Angular.js and like...

<img
  ng-src="{{myCtrl.myImageUrlThatWillDynamicallyChange}}" 
  onerror="this.src='data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=='"
  />

it's basically a shortest transparent GIF (as seen http://proger.i-forge.net/%D0%9A%D0%BE%D0%BC%D0%BF%D1%8C%D1%8E%D1%82%D0%B5%D1%80/[20121112]%20The%20smallest%20transparent%20pixel.html )

of course this gif could be kept inside some global variable so it won't mess up the templates.

<script>
  window.fallbackGif = "..."
</script>

and use

<img
  ng-src="{{myCtrl.myImageUrlThatWillDynamicallyChange}}" 
  onerror="this.src=fallbackGif"
  />

etc.

Jacek Głodek
  • 2,374
  • 1
  • 14
  • 8
0

Just simply add blank alt attribute on your <img>

Something like this: <img src="..." alt="">

-1

Just Use simple css

.AdminImageHolder {
display: inline-block;
min-width: 100px;
max-width: 100px;
min-height: 100px;
max-height: 100px;
background: url(img/100x100.png) no-repeat;
border: 1px solid #ccc;
}