Articles :: JavaScript :: AlphaPNG for the masses

written by Toby Miller on September 22, 2005
September 22, 2005

AlphaPNGs (32-bit PNG graphics with alpha transparencies) allow us to use alpha transparencies for things like drop shadows, anti-aliased edges, opaque color washes, etc. The question marks floating on this article have actual drop shadows (embedded in the graphic) and the red shell spiral shown lower is a transparent png with a 50% opacity. Notice that you can see through it, that's the alpha transparency.

The Problem

This has natively worked in most browsers for years ... except for IE (Internet Explorer), the thorn in most web developers side. So for IE we use a css filter (which only IE recognizes) to turn on the alpha image loader (the tucked away proprietary method used by IE to support these graphic formats). There are rumors that they wouldn't openly support this format due to some kind of kickbacks from Compuserve because they didn't want the GIF file format to lose it's royalties from Adobe .... blah blah blah. Anyhow, they do support it, they just don't want to advertise it so it's not enabled. The good news is that you can enable it yourself with a little bit of CSS and, to make it a little more hands off, a little bit of JavaScript.

As an update on the Internet Explorer front I'd like to say that they DID fix this with Internet Explorer 7. So this solution only applies to Internet Explorer versions prior to 7. At least that means that some day this "fix" will no longer be required.

Before you start hailing the awe and glory of the PNG format, which it no doubt does deserve take a quick minute to first determine if PNG is even the right choice for your image. It's not always the right choice for several reasons (unless your soul focus is on achieving alpha transparency). Here are some quick descriptions of what uses are appropriate for each format.

PNG 8-bit

This format is appropriate for images requring few colors (no more than 256) to show a simple illustration or small photograph, one transparent color is allowed.

PNG 24-bit

This format is appropriate for images requiring many colors (up to 16,777,216) to show a complex illustration or photograph in a non-lossy compression format (more detail than JPEG, but larger files).

PNG 32-bit

This format is appropriate for images requiring many colors (up to 16,777,216) to show a complex illustration or photograph in a non-lossy compression format with an additional need for alpha transparency masking (for drop shadows or semi-transparent colors or truly smooth anti-aliased edges).

JPG

This format is appropriate for images requiring many colors (up to 16,777,216) to show a complex illustration or photograph in a lossy compression format (less detail than PNG, but smaller file sizes).

GIF

This format is appropriate for images requiring few colors (no more than 256) to show a simple illustration or small photograph or short animation sequence, one transparent color is allowed.

Okay, I'm done lecturing now so on with the solution.

The Solution

CSS-only solutions do exist out there for this problem, but I really hate manual intervention and prefer to automate whenever possible. So my solution is based on the use of Autonomous JavaScript practices. What that means in laymans terms is that the JavaScript finds the PNG images on my page and "fixes" them for Internet Explorer without me telling it which particular images it should be looking at.

In order to use this script all you need to do is change the spacerImage variable to reference the path to a clear spacer graphic on your website, load this JavaScript file into the HEAD of your HTML document and convert any backgroud-image calls for alpha-transparent PNG images from external CSS rules to inline CSS style parameters. This script is unable to read and manipulate your external CSS rules. If you know of a way around this for Internet Explorer then I'd be very interested in seeing it.

source code:
   1:/**
   2: * An alpha transparent png support library for Internet Explore (other browsers
   3: * support this functionality natively.
   4: *
   5: * @author Toby Miller <tmiller@tobymiller.com>
   6: * @copyright Copyright (C) 2005, Toby Miller
   7: * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
   8: */
   9:
  10:/**
  11: * define spacer image used by alphapng functions
  12: */
  13:var spacerImage = '/img/spacer.gif';
  14:
  15:/*
  16: * DO NOT EDIT BELOW THIS LINE
  17: */
  18:
  19:/**
  20: * fix alpha png backgrounds on a page (turn on transparency for IE)
  21: * Not needed for IE7 and Opera, but Opera passes the document.all test, so we need to put this in there as well
  22: * @param string support html tag (i.e. "DIV")
  23: */
  24:function _fixAlphaPngBackground(htmltag)
  25:{
  26:    var src     = '';
  27:    var ua      = '';
  28:    var rpng    = new RegExp('url(([a-zA-Z0-9_/:-]+.png))');
  29:    var rmsie   = new RegExp('msie');
  30:    var rmac    = new RegExp('mac');
  31:
  32:    if ((document.all) && (navigator.userAgent.toUpperCase().indexOf('MSIE 7') < 0) && (navigator.userAgent.toUpperCase().indexOf('OPERA') < 0))
  33:    {
  34:        var l = document.getElementsByTagName(htmltag).length;
  35:        for (var i = 0; i < l; i++)
  36:        {
  37:            src = document.getElementsByTagName(htmltag)[i].style.backgroundImage;
  38:            ua  = navigator.userAgent.toLowerCase();
  39:
  40:            if (src.match(rpng) && ua.match(rmsie) && !ua.match(rmac))
  41:            {
  42:                src = src.replace(rpng, '$1');
  43:                document.getElementsByTagName(htmltag)[i].style.backgroundImage = 'none';
  44:                document.getElementsByTagName(htmltag)[i].style.filter = 'progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled='true', sizingMethod='scale', src='' + src + '')';
  45:            }
  46:        }
  47:    }
  48:}
  49:
  50:/**
  51: * fix alpha pngs on a page (turn on transparency for IE)
  52: * Not needed for IE7 and Opera, but Opera passes the document.all test, so we need to put this in there as well
  53: */
  54:function fixAlphaPng()
  55:{
  56:    var src     = '';
  57:    var ua      = '';
  58:    var width   = '';
  59:    var height  = '';
  60:    var rpng    = new RegExp('.png$');
  61:    var rmsie   = new RegExp('msie');
  62:    var rmac    = new RegExp('mac');
  63:
  64:    if ((document.all) && (navigator.userAgent.toUpperCase().indexOf('MSIE 7') < 0) && (navigator.userAgent.toUpperCase().indexOf('OPERA') < 0))
  65:    {
  66:        for (var i = 0; i < document.getElementsByTagName('IMG').length; i++)
  67:        {
  68:            src     = document.getElementsByTagName('IMG')[i].getAttribute('src');
  69:            ua      = navigator.userAgent.toLowerCase();
  70:            width   = document.getElementsByTagName('IMG')[i].getAttribute('width');
  71:            height  = document.getElementsByTagName('IMG')[i].getAttribute('height');
  72:
  73:            if (src.match(rpng) && ua.match(rmsie) && !ua.match(rmac))
  74:            {
  75:                document.getElementsByTagName('IMG')[i].setAttribute('src', spacerImage);
  76:                document.getElementsByTagName('IMG')[i].style.filter = 'progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled='true', src='' + src + '', sizingMethod='scale')';
  77:                document.getElementsByTagName('IMG')[i].style.width = width + 'px';
  78:                document.getElementsByTagName('IMG')[i].style.height = height + 'px';
  79:            }
  80:        }
  81:
  82:        _fixAlphaPngBackground('DIV');
  83:        _fixAlphaPngBackground('TABLE');
  84:        _fixAlphaPngBackground('TD');
  85:    }
  86:}
  87:
  88:/**
  89: * @requires common.js:addEvent
  90: */
  91:addEvent(window, 'load', fixAlphaPng);
  92:

Download Source Code

Known Problems

It's been reported by some people about how much they hate the gray flicker that this solution causes in Internet Explorer. This is caused by the fact that Internet Explorer renders the alpha transparency mask on alpha transparent PNG images as a solid gray color. Therefore, what you're actually seeing is the un-filtered PNG image being loaded (that's the gray background) and then the alpha filter being applied (that's the JavaScript fix applying the clear spacer gif in place of the gray background). There are ways around this but they all require us to go back to manual intervention or to use a server side solution over the client side solution. If you find yourself in need of one of these other solutions because the gray flicker is just unacceptable then shoot me a line and I'll get you pointed in the right direction.

I hope this information was useful. As always let me know if you have any questions, find mistakes in my code or just want to chat about the topic.

permalink                                                                                                                                                                          
   Natural Living (5)
      Heating & Cooling (1)
      Herbal Remedies (1)
   Personal (0)
      Family (1)
      Humor (11)
      Miscellaneous (1)
      Politics (5)
   Technology (2)
      System Administration (4)
            Linux (1)
            Solaris (0)
      Web Development (2)
            CSS (3)
            Design (1)
            Flash (1)
            JavaScript (11)
            PHP (1)
                        CakePHP (1)
            Web Browsers (2)
                        Firefox (1)
                        Internet Exploder (0)
                        Netscape (1)
printed @ tobymiller.com
(currently rendering CSS for Internet Explorer)(currently rendering CSS for non-Internet Explorer browsers)