Main Page Content
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 backgroundfunction 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.