robert hahn

a darn good web developer

March 28, 2006

Building Web Sites with Transparent PNGs

Designing a web template with transparent PNGs so that they work in all browsers can be a bit of a tough nut to crack, and I’d bet that we’d be seeing a whole lot more transparent goodness on the web if people understood it better.

Let’s cover the easy ground quickly. You probably already know that 2 of the top 3 browser engines (Gecko-based and Safari) support transparent pngs properly. And you probably know that the odd one out is MSIE 5-6. You’ve probably already seen resources where they talk about how you can enable transparency for MSIE using css, or maybe even used the JavaScript based solution. Yes, there are tradeoffs, but if you want the eye candy, then they’re pretty easy to make.

Nothing I’ve seen in my research talked about the hell I had to go through to get pngs to work for me. The pngs themselves weren’t the problem, it was how I wanted to use them: as background images.

Naturally enough, when I wanted to use a background image on some bit of markup, I can make use of the various background-* properties in CSS, right? The problem comes when I needed to leverage the msie fix. A line like this in your CSS file:

filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(enable='true',src='/images/theme/tint.png',sizingMethod='scale');

doesn’t give you a background image. It gives you an image that’s as much a peer as any other image placed on your page with the <img /> tag. And that means that you lose out on the advantages of positioning your background image, aligning it, or specifying which direction you want it to repeat.

That sucks, man.

There is a way to fix this. What it boils down to is recognizing that you’re working with images, not background images, and planning your design accordingly.

Let’s take a look at my site here. You see the dropdown menus, and this is probably the simplest place to start understanding what you need to do.

When my site broke on MSIE, The menu code looked a bit like this:

<div id="archives_menu" style="display: none;" class="menu">
    <ul>
        <li><a href="/articles/2006/03">March 2006 <em>(2)</em></a></li>
        <li>...</li>
    </ul>
</div>

You can see the stylesheets here and here. I use conditional comments to load in the MSIE code.

To get the menu to look the way it does, I used 3 background images. The top image, with the two vertical lines, resides in the <div /> layer, and is covered by the div.menu {} rule (about 4/5 down the page). The child <ul /> tag (covered with the div.menu ul {} rule) gets the bottom cap, and the list items get a vertically running middle.png, and this is covered with the div.menu li {} rule.

This is an elegant solution. I’m making great use of the minimum amount of markup needed to solve the problem. And it won’t work in MSIE. Why? In this case, I don’t exactly know. But as long as I try to treat them like real images, not background images, things look a whole lot better. Let’s look at the after state.

<div id="archives_menu" style="display: none;" class="menu">
    <div class="menu_top"></div>
    <ul>
        <li><a href="/articles/2006/03">March 2006 <em>(2)</em></a></li>
        <li>...</li>
    </ul>
    <div class="menu_bottom"></div>
</div>

Not a whole lot different; I had to throw in a couple of extra <div /> tags. in the beachboy.css file, these <div />’s do nothing. in the msie.css file however, we do some fun stuff. First of all, we clear out the background images by setting

background-image: none !important;

wherever we need to. Then in div.menu_top {}, I set the top cap of my menu in that tag, and flesh it out with some width/height data. I do the same thing indiv.menu_bottom {}. Finally I take the middle image and set it to scale as a ‘background’ of sorts on the <ul /> tag. Everything works. Almost. The links wouldn’t work, but the fix for that is found in the div.menu ul li {} rule - the position: relative; statement. I can only surmise that what that’s doing is ‘popping’ the link up over the png so that click events on the link can be registered.

You’ll see that I used this approach, with some variations, on other parts of the design. The big image in the upper right side of this design was particularly troublesome, because no matter where I wanted to set my position: relative rule, the links wouldn’t work. I ended up creating a new empty div to store this image in for the MSIE browsers, positioning that, then removing the background image from the original spot. I still needed to use position: relative; of course, but at least that trick worked this time.

Is this clear enough? Do you get what I had to do to get this to work? I’m sure the solution will offend some of the purists, given the empty tags, and I can respect that. I aspire to be a purist in my work as much as possible. But when I want a particular effect, I’ll do the pragmatic thing and lower the bar just enough to get things to work.

The best part is, when MSIE 5-6 becomes obsolete, the cleanup is super quick – remove the empty <div />’s and delete the conditional comment. I can live with that.

decorative image of trees

Copyright © 2009
Robert Hahn.
All Rights Reserved unless otherwise indicated.