A quick and dirty CSS hack: PNG backgrounds

With the expanding support for PNG, it has become more and more frustrating to be prevented by IE's lack of support to fully use PNGs. We will try to find a way to bypass IE's limitations (until the next vesion comes out and hopefully solves the problem) by showing it what it can display, and by giving PNGs to more modern browsers.

Quick definitions

PNG
Portable Network Graphics. This format was designed as a means to replace GIF, originally because of a royalty question. But it expands GIF's transparency capacity by managing full 256-level alpha-transparency. See the W3C's recommendation.
GIF
Graphics Interchange Format
This format is not royalty-free, and has limitations. Yet it has been a de facto standard for transparent images on the web since the 89a implementation.
CSS
Cascading Stylesheets. But you knew that, didn't you?

For a more detailed description of the technical aspects of both, please refer to To PNG or not to PNG.

The situation at hand

So, Internet Explorer does not manage PNGs but you would very much like to have a nifty semi-transparent background to blend it better with your background. So far the solutions for IE have mainly involved Javascript, as a simple javascript alpha transformation method (see the example below), or more subtly, as a behavior method after the example of WebFX.

A 'simple' javascript alpha transformation method: too many drawbacks!

This is what I found, with the help of the Pompeurs mailing-list: Internet Explorer can replace a background by another, and in the process get the exact alpha transparency for each pixel of the new background image. Then it applies a filter and gives the expected result: alpha-transparency!

// this function finds the 'logo' element in my HTML and replaces its background

function init() {
  // is the browser competent with the DOM?
  if(document.getElementById) {
    // is the browser capable of managing runtimeStyle?
    // (this would mean, basically, "hey, I'm IE")
    if(document.getElementById('logo').runtimeStyle) {
      // delete current background
      document.getElementById('logo').style.backgroundImage = 'none';
      // apply PNG background with alpha transparency filtering
      document.getElementById('logo').style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='logo.png',sizingMethod='scale')";
    }
  }
}

window.onload=init;

But there are serious drawbacks with this method, which I have learnt the hard way:

  • It relies on the onload event handler. And of course many people will not end the loading properly, for various reasons: they can have a bad connection that interrupts the download, they can stop it themselves because the page is crammed with images and they're only interested in the text, not the pictures, etc.
  • Some browsers understand some but not all of the code. Opera 6 on my machine shows nothing at all, there's a block somewhere and I haven't found where yet (and won't look for a solution either, because of what I just said about relying on onload).

Hacks are to be avoided, yet they're sometimes unavoidable

I fully endorse Peter-Paul Koch's statement: Keep CSS Simple! For those of us who have been in the web trenches for a few years, hacking around one browser's limitations reminds us of countless nights writing proprietary javascript, proprietary tags, multiple versions of a given page, and whatnot. Yet like with many things in life, simple hacks are sometimes unavoidable; but in this case they should be as limited as possible: extensive hacking means sleepless nights, trust us.

There are simple and not-so-simple ways to hide some CSS to some browsers, mainly based on their flawed implementation of constantly-improving CSS standards. There are even pretty complete lists of more or less ugly hacks based on commenting and commenting-into-comments, backslashing, etc. See Centricle's CSS filters chart for a pretty thorough example.

What? Did I say "ugly" a second ago? Sorry to sound pejorative. I meant it is going quite difficult to maintain and re-read your CSS in a few months' time when you write this: /*/*//*/property:value;/* */ or that: /*/*/property:value;/* */. You have to write extensive documentation and keep it at hand, right?

OK, hacks are ugly, but here is a simple one I found while dealing with the issue: IE (like all the old browsers) does not understand child selectors (the > character). So let's give IE what it wants: a GIF background. More modern browsers will display the PNG, because one expects them to both understand the child selector and be able to display PNGs properly.

What about this piece of CSS code:

/* this line give you a nice, if less sexy, GIF background */
div.bg_hack { background:url('ceci_est_un_gif.gif') no-repeat top left transparent; }

/* PNG power! */
body > * div.bg_hack { background:url('ceci_est_un_png.png') no-repeat top left transparent; }

Here is the GIF/PNG background hack in action.

Side note

Since I came up with this idea, an article about CSS drop shadows was published on A List Apart that uses IE's inability to understand the !important CSS statement. Fair enough, it's yet another way to do the same thing. But for the sake of readability I prefer to stick to the child-selector for the time being.

Conclusion

Of course this is a hack, so it can generate problems on its own. Non-flat-colored backgrounds can show the rugged edges of the GIF in Internet Explorer (this is what I show in my example, see the funky part of the page. And either because of petitions, or because people at Microsoft are clever and will modify subsequent versions of IE, or just because history will force them to do so (and this is not the place to discuss this), one day or another we may end up finding this hack unnecessary.

Until then, this will do the trick, in my book.

Afterword

Please feel free to report any weird behavior. So far I have tested it with Opera, Mozilla, IE5.5/Win and it behaves like it should. I have no access to Safari, for example, but I hear its CSS support is excellent.

Comments

Opera6 and the first example.

The reason it doesn't work in Opera6 is that the DOM support in this browser was still flawed. Opera6 triggered at getElementById, but failed to use it properly, hence to block out O6, you can do a document.getElementById && document.createTextNode.

more on that here: DOM tests on quirksmode.org

Re: Opera 6

Thanks for the tip Chris.

I was sloppy in my browser testing, I guess. I've never tested much for Opera. My bad.

Anyway that still leaves us with the same problem, doesn't it ;)

weird behaviour

I cannot tell you if what my browser shows me is weird behaviour, because you did not provide a reference screenshot. Evolt's fault, really; their editors should have let you make one. IE 5.0/Win shows a grey background in all four PNG examples.

Re: weird behaviour

Branko,

Evolt's fault, really; their editors should have let you make one.

Heh. I'm one of them ;)

My method is supposed to simply hide the PNG from IE, all versions. Can you send me a screenshot (my email address is at the top of this page) or post a URL here?

why use this instead of WebFX's method?

What advantage does this method have over WebFX's pngbehavior.htc [1]? It seems to me that their solution is even cleaner CSS (one additional rule, no hacks), and has the major advantage of actually making the PNG work properly! I've used it on several sites.

[1] http://webfx.eae.net/dhtml/pngbehavior/pngbehavior.html

Next version of Microsoft Internet Explorer...

We will try to find a way to bypass IE's limitations (until the next vesion comes out and hopefully solves the problem)

(Umm, it doesn't: MozillaZine: Internet Explorer 6 Service Pack 1 to be Final Standalone Version.)

Two replies in one...

cjm46543: The behaviour is mentioned in my article, I've tried it of course... but it adds non-validating CSS, and my purpose here was to try and find a validating method, be it only for the sake of theoretical experimentation.

asjo: Yes, I know it: there won't be an IE7 (or someone will do a collection of IE behaviours and name it IE7 as a kind of joke), IE will be an indissociable component of the next version of Windows. I did not want to enter into specifics here, and thought it best to just write "next version" rather than complicate matters by telling possible non-specialists "until the next version of Windows comes out and in it the embedded, with-Windows-only, newer version of IE".

incredible...

I know that most of the professional webdesigners here have no choice but for my personal site, I care less that IE does not support PNG. Beyond royalities, there are tons of times where PNG would work so much better than GIF. I think it is very tragic and yet to be expected that IE does not support a standard and all the other major browsers do.

Other PNG Issues

They are not many articles or tutorials about using PNGs

One issue I had before besides the IE hack was optimizing file size. One png image I was working with was over 200KB in size. Does anyone have suggestions about programs that can optimize PNG compression better than Photoshop CS

Thanks,
Buddy

File size using PNG

The most simple solution is using Fireworks. Saving, using the default settings of Fireworks will result in a much smaller file size
HFdesign Webdesign

PNG for Logos and Casting Shadows

I found that PNG images are very good for logos and have become very popular in the blogosphere. PNG images should also be used if you want to lay a shadow down from one image on top of whatever it is resting on. To do this, you will need to provide a transparent background layer in photoshop and build your logo or image on layers that are above the background layer. If you are working these types of files, the size shouldn't present that large of an issue. Thanks, Brad Henry

Thank you very much for this

Thank you very much for this great article! The PNG transparency problem drove me crazy already! Thanks again! Regards Smaaz

Nice

Stephane, that was a nice hack. In most websites i find thet PNG is used in icons only. There are very less websites which use PNG as background.