Detecting if images are disabled in browsers

I received an email from an old friend and colleague pointing out that with images disabled in the browser, the support information in the data tables on HTML5Accessibility.com disappears. An issue and an embarrassment! This has now been fixed.

Detecting if images are disabled in browsers

I went searching on the internet to find a suitable script for detecting if images are displayed or not. I found this post Use Javascript to detect if images are disabled.The script appears to work fine in Internet Explorer and FireFox, but not in Chrome and Opera ans Safari. It also looked a bit complex for me. What I wanted was a simple method that worked cross browser.

The problem

To be clear, what I am referring to in this case is inline images, though the same method will work with CSS images as long as there is one img element on the page to test. On HTML5Accessibility.com the following pattern is being used, the CSS for which I borrowed from CSS in Action: Invisible Content Just for Screen Reader Users.

HTML

<img src="images/cross.png" width="16" height="16" alt="">
<span class="hidden">Not supported</span>

CSS

span.hidden

{
position:absolute;
left:-10000px;
top:auto;
width:1px;
height:1px;
overflow:hidden;
}

This works great if you have images enabled (the presence of the images are not announced by screen readers due to the use of alt=”” and the text is announced, although it is not on screen), but not if you don’t, because the images are not displayed and the text is still hidden off screen, d’oh!

Major modification 19/08/2012

Thanks to @thierrykoblentz for providing a much simpler method (offsetWidth) to check whether images are enabled/disabled!

After testing more found offsetWidth alone was unreliable in IE, so have gone back to more complex check using readyState in conjunction with offsetWidth. Thanks anyway @thierrykoblentz!

Tested in Firefox/Opera/Chrome/IE on windows all work fine!

Try the updated test page in your fave browser/OS.

The noImage() script

function noimage()
{

if ((document.getElementById('flag').offsetWidth==1&&document.getElementById('flag').readyState=='complete')||(document.getElementById('flag').offsetWidth==1&&document.getElementById('flag').readyState==undefined))

{
var objHead = document.getElementsByTagName('head');
var objCSS = objHead[0].appendChild(document.createElement('link'));
objCSS.rel = 'stylesheet';
objCSS.href = 'alt.css';
objCSS.type = 'text/css';
}

}

//add to body

<body onload="noimage();checkHC();">
<img id="flag" src="clear.gif" alt="">

What  the script does

It checks the value of the offsetWidth property of a 1 x 1 pixel image added to the top of the page. if the check returns true, images are enabled, if false images are disabled.   If images are enabled  it adds and external style sheet containing the style rules to hide the text off screen.  By default the text and images are visible, so that the text will be visible if users have JavaScript disabled. 

Checking for Windows High Contrast

It also seemed like a good idea to have the text visible when Windows high contrast mode is enabled (shift + alt + print screen keys), so I added the following function (borrowed from the AOL AXS script library), that checks if Windows high contrast mode is enabled. If it is enabled both images and text are displayed.

function checkHC() {

var e,c;
//Create a test div
e=document.createElement("div");
//Set its color style to something unusual
e.style.color="rgb(31,41,59)";
//Attach to body so we can inspect it
document.body.appendChild(e);
//Use standard means if available, otherwise use the IE methods
c=document.defaultView?document.defaultView.getComputedStyle(e,null).color:e.currentStyle.color;
//Delete the test DIV
document.body.removeChild(e);
//get rid of extra spaces in result
c=c.replace(/ /g,"");
//Check if we got back what we set
//If not we are in high contrast mode
if (c!="rgb(31,41,59)"){
return true;
}
}

I then wrapped then wrapped it all together and added it to HTML5Accessibility.com. There is also a test page available. The scripting is by no means elegant, if anybody wants to improve it please do!

Categories: Technical

About Steve Faulkner

Steve was the Chief Accessibility Officer at TPGi before he left in October 2023. He joined TPGi in 2006 and was previously a Senior Web Accessibility Consultant at vision australia. Steve is a member of several groups, including the W3C Web Platforms Working Group and the W3C ARIA Working Group. He is an editor of several specifications at the W3C including ARIA in HTML and HTML Accessibility API Mappings 1.0. He also develops and maintains HTML5accessibility and the JAWS bug tracker/standards support.

Comments

Artur Ortega says:

You don’t need the hidden span for the text. You can use the ALT attributes with:
img:after{content: ” (” attr(alt) “)”;}

Steve Faulkner says:

Hi Artor,
I can’t get that to work with img. I also think that text added via CSS is not well supported by assistive tech.

Why load in a separate stylesheet? Why not just add a class to the body element (say class=”no-images”) and then use the cascade of CSS to trigger your styles?

Steve Faulkner says:

hi Russell,

Why load in a separate stylesheet?

No particular reason, doing as you suggest could also achieve the same result.

Using naturalWidth to detect supports works in Opera for me, but it appears that due to caching of images, we report the width even when disabled. I’ve filed a bug for this (CORE-42117) and will look into fixing it. In the mean-time, one way to work around the issue is to ensure that the image is never cached, either by HTTP headers or a hack like this:

var img = document.querySelector(‘img’);
img.src += ‘?nocache=’+Math.random();
window.onload = function() {
var imgEnabled = document.querySelector(‘img’).naturalWidth > 0;
alert(imgEnabled);
};

However, Mathieu ‘p01′ Henri came up with a much neater solution that works at least in Opera:

var imagesOn = (function(){var i=new Image();i.src=’data:image/gif,GIF89a%01%00%01%00%80%00%00%00%00%00%FF%FF%FF!%F9%04%01%00%00%00%00%2C%00%00%00%00%01%00%01%00%00%02%01D%00%3B’;return!!i.width})();

(It appears that caching doesn’t apply here, it works even when I toggle images on and off a few times.)

Steve Faulkner says:

Thanks Philip and Mathieu ‘p01? Henri , have added the function, now works with Opera too!

Joe Schunk says:

In Safari for Windows, if you turn on the “Developers” menu there is a menu selection for “Disable Images”. See Safari 3.1 (Windows) Developer tips

Steve Faulkner says:

Hi Joe,
yes I actually worked it out prior to publishing the article, but forgot to take out the sentence about not being able to disable images in Safari. Thanks for bringing it to my attention.

I would suggest trying make make it work without the checks for window.opera, this is the kind of thing that ends up being copied around and in some cases makes sites break when we fix the bugs they originally worked around. Not sure if this is such a case. Probably the short imagesOn snippet is enough for all browsers that support data: URIs, not just Opera.

I also fixed the bug I filed about naturalWidth/Height returning something > 0 if the image happened to be cached, which I assume is what messed up your testing in Opera initially.

Hi Artur,

pseudo-elements don’t work on images.

Steve Faulkner says:

Hi Philip,

I would suggest trying make make it work without the checks for window.opera

I did try, but found that the value of imagesOn was always false in IE and sometimes true in firefox when it should have been false. So needed some way to isolate the checking of the variable to Opera. If you can work out a better way that does not rely upon the window.opera check please share. I state in the article my JavScript skills are limited.

dioneo says:

correct, :before and :after only work on elements that can have content (read:html) inside. So not on IMG, BR, HR, INPUT and such.
Opera supports
IMG { content: attr(alt);} that I misuse for not displaying/requesting images on mobile if needed.

Hi Steve,

I used to use a much simpler technique. So looking at your solution I’m now wondering if I’m not missing something with my basic approach.
Back in the day, when we used a shim for various reasons, I was checking the width of that image:

document.getElementById(“shim”).offsetWidth !== 1)

With images turned off, I would not get that 1 pixel width and that seemed to work fine. I used the logo of the site when not using a shim (any image that I knew would belong to the page).

Steve Faulkner says:

Hi Thierry,
It may well be that there is a simpler solution, I didn’t find one when searching. I quickly tried out your code snippet but didn’t get a difference with images turned off/on. Can you provide a more complete test?

John says:

Using JavaScript to detect if images are disabled in a browser?

Isn’t it likely that a browser with images disabled also has JavaScript turned off?

Steve Faulkner says:

Hi John,
I have no idea if there is a strong relationship between having images turned off and JavaScript disabled, do you? Note that if Javascript is disabled the default display is for the text to be dsiplayed along with the image. So in either case when Javascript is disabled I have implemented it so if images on or off the user gets the required information.

Hi Steve,

I tried the following snippet – on this page – in the console:

alert(document.getElementsByTagName('img')[0].offsetWidth !== 60)

The first image seems to be an avatar image which is 60 pixels wide. With “image on” the above returns false, but with “image off” (i.e. disabled via the dev toolbar), the above returns true.

Steve Faulkner says:

HI Thierry,
Works for Firefox, does not appear to work for IE, Opera, chrome, Safari.

Hi Steve,

It seems to work fine on my end. Could you please check this test page for me? Ater all, this is very basic so I don’t see why it would fail 🙁

Nick J says:

Should :
((document.images[0].readyState='uninitialized'&&
be:
((document.images[0].readyState=='uninitialized'&&

I.e. comparison, not assignment?

Steve Faulkner says:

Hi Thierry,
tested and found to work great, have updated script accordingly, thanks you very much!

Steve Faulkner says:

Hi NickJ,
correct, but also moot as Thierry has provided a much neater solution. thanks for pointing it out anyway.

Hi Steve,

Sorry to highjack your article like this; feel free to delete this comment 🙂

But two things I wanted to add:

– There is no need for the “shim” per say. Authors can avoid the extra HTTP request by using any existing image in the document (as long as the check is done against that image’s width).

– Instead of plugging a styles sheet, which also creates an extra HTTP request, authors can plug a class on the html or body element and then style accordingly. For example:

.hidden {
...
}
/**
* Images are off we reset the previous rule
*/
.imageOff .hidden {
position:static;
width:auto;
height:auto;
}

The other advantage of this approach is that it should reduce the risk of a Flash Of Unstyle Content (since the element would be hidden from the start).

Steve Faulkner says:

Hi Thierry, no problem, I wrote the post to resolve a problem, you and others have been helping to make the solution better, any input is appreciated! I will update the script accordingly when I get a chance.