Background-Position PNGs. Yes, Even in IE6…

Background:

If you’re reading this, you probably already know the issue with trying to background-position PNGs in IE6, so I’ll make this as brief as possible (skip down to the Demo if you’d rather):

  • A somewhat-little-known fact is that IE6 actually does display PNG8-format PNGs just fine, but PNG8s can’t handle semi-transparency, which is why most people choose PNGs over JPGs or GIFs in the first place, so most people tend to think that IE6 simply can’t do PNGs at all.
  • PNG24-format PNGs, however, do a wonderful job of displaying semi-transparency, but to display PNG24-format PNGs in IE6 you have to use Microsoft’s proprietary filter in your CSS.
  • However, when you apply a background image via filter, you cannot position that background image (like when you want to use a sprite)…
  • So, developers usually end up either figuring out a way to make GIFs handle the job, scrap the sprite and go the route of individual PNGs, applied via filter, or create two versions of the sprite, one as a nice PNG24, the other as a GIF with some anti-aliasing to help “ease” the transparency…  but all of these options suck.

So, how much would you pay for an option that allowed you to use the same background sprite image, as a PNG24, and still be able to position it in IE6?  Well, luckily for you, there is a sale on today…

Demo

Here is my demo. You can view the source and probably see just about everything you need to know, but I’ll take up some real estate on this page and explain it all anyway…

In pseudo-code, what we are going to do is apply the background image to an element (a <p>) that is as large as the background image itself, place that element inside another element (an <li>), then absolutely position that first element, rather than the background image, faking a background-position… If that doesn’t make much sense, completely understandable, it barely does to me, please read on…

Here are a the only two screen captures that really matter: FF3.5.2 and IE6. (I say only these two matter because IE6 is the unruly child we’re trying to civilize and FF serves as the proper example; once it works in FF, I find mostly, it works in the other modern browsers.)

There are three parts:

  1. the background image,
  2. the HTML, and
  3. the CSS.

Background Image

We start with the background PNG.  A very simple PNG24 image, three big circles, three small circles, each with a drop-shadow that demonstrates semi-transparency.

HTML

Next, we look at the meat-and-potatoes of the HTML:

<li class="sticker large">
<p class="green"></p>
<span>Large Green</span>
</li>

You’ll note that the <li> has two classes: sticker and large. sticker is the “generic” class, which handles a majority of the CSS, and large is specific to the CSS for the large circles (the small circles get class="sticker small").

You’ll also note that the <p> has a class of green, which tells the CSS to position the background image to show the green circle. (Of course, it would be great if we could simply place all the classes on the <li>, but IE6 confounds us yet again but not being able to acknowledge multiple classes in CSS statements such as .sticker.small.green{...}; in this case, IE6 ignores .sticker.small and applies the CSS to any element with a class of green… I can only handle so many bugs at once…)

The <span>Large Green</span> is simply text that I want to float over the background image. In the right-column of the demo page, these <span>s are <a>s, just to show another scenario.

CSS

And now let’s have a look at the CSS (there is a fair bit, so I’ll break it into pieces, addressing each as I go):

.sticker {
position:relative;
top:0;
left:0;
width:88px;
height:88px;
overflow:hidden;
}

We make the <li> relative to contain the elements we’re going to position absolutely, give it a size and hide any elements that are bigger than those sizes (like the <p> we are about to see).

.sticker p {
position:absolute;
top:0;
left:0;
width:174px;
height:440px;
background:none;
filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='background-position-png.png',sizingMethod='crop');
}
.sticker > p {
filter:none;
background:url('background-position-png.png') no-repeat;
}

In the first declaration, we make the <p> absolute so we can move it around, give it a size and, initially, apply the background PNG using Microsoft’s filter. In the second declaration, we create CSS that IE6 cannot read (using the child selector), clearing the filter and applying the background image properly for everyone except IE6.

.sticker span, .sticker a {
position:absolute;
z-index:1;
top:50%;
margin-top:-1.2em;
width:80px;
display:block;
font-size:1em;
color:#fff;
text-transform:uppercase;
text-align:center;
}
.small span, .small a {
font-size:.8em;
}

This gives a little style to the <span> or <a>, if you need some form of text over the background image. The key part is that these elements are positioned absolutely, with the top and z-index set. The margin-top is to help get the vertical alignment “just right” and might vary based on the font-size you choose. The rest of this CSS is personal preference.

.small p {
left:-95px;
}
.sticker .red {
top:0;
}
.sticker .green {
top:-90px;
}
.sticker .blue {
top:-180px;
}

And all of this is to help extend the flexibility of the sprite: if it is a small sticker, the “background” (remember, not the image, but the <p> that contains the background image) element is shifted to the left; the color classes shift the <p> up and down to further adjust the appearance of the background image (the <p>).

And that’s pretty much it! So, hopefully my pseudo-code makes more sense now: we’re applying the background image to an element, then we’re positioning the element, not the background image

Granted, this approach does require a little extra mark-up, but really just an opening and closing <p>, which I don’t think is too high of a price to pay to be able to position a PNG24 sprite as a background image in IE6, right?

Give it a go and let me know what you think.

Cheers, and happy positioning,
Atg

Leave a Reply

Your email address will not be published. Required fields are marked *