Backslider: A workaround for background positioning PNGs with IE6
Aug 02, 2010
How many times have you run into this problem?
You have a translucent PNG for which you had to run the AlphImageLoader trick to get IE6 to render properly. Everything is great, except this PNG is a sprite, and you also need to change the background-position, such as for a hover or focus state. Cue the sad clown kazoo. Oh well, I guess IE6 doesn’t get a hover state, right?
That’s what I thought too, till I thought of this handy little trick.
Setting the stage
Usually with this sort of situation, I am using an image that is a sprite which contains three states of the same image: The default, hover, and active state. Then I use background-position to move that sprite to where I needed it.
Take the following example:
This is a navigation element with the following code:
<li><a href="/new">New Post</a></li>
Normally, we’d do something like this to show a nice pretty title for this link:
#new a {
width: 99px;
height: 39px;
display: block;
text-indent: -9999em;
background-image: url(/m/titles/new-post.png);
background-repeat: no-repeat;
background-position: 0 0;
}
Of course this is a sprite, so the actual image for it is (Note: For this example I gave it a dark background so you can see it):
And for hover & focus classes we’d do something like this to expose the hover version of the image:
#new a:hover, #new a:focus { background-position: 0 -39px }
And we would do something similar for the active version and the on-state:
new a:active, #new a.on { background-position: 0 -79px }
This all well and good, but as you may know, since this is a translucent PNG, none of these hover, focus, active or on states are an option with background-position for IE6, since background-position does not work with the AlphaImageLoader filter fix. The only alternatives are to just do without these states, or to cut separate image for each state and write separate lines in CSS to pull said images in under each condition. That’s a messy solution that, despite being pretty sub-optimal, is a heck of a lot of extra work.
What if there were a better way? I think there is, and this is my solution: I named it ‘Backslider’. I know, it’s silly.
Backslider
When you think about what background-position really is doing, it’s moving an image around a mask, based on specific events or situations. The trick is, that you don’t need background-position to do this, and often we don’t need any more markup than what is already available to solve this problem.
Remember, what we’re dealing with is a link inside of an #new element. Let’s use that #new element to provide the mask, and then move around the #new element using absolute positioning. CRAZY, RIGHT?!
#new {
position: relative;
width: 99px;
height: 39px;
overflow: hidden;
}
#new a {
display: block;
width: 99px;
height: 117px;
position: absolute;
top: 0;
left: 0;
text-indent: -9999em;
background-image: url(button-sprite.png);
background-repeat: no-repeat;
background-position: 0 0;
}
#new a:hover, #new a:focus { top: -39px; left:0; }
#new a:active, #new a.on {top: -78px; left:0; }
In the IE stylesheet you can still apply the filter fix for the new-post.png. But because you’re not using any sort of background-position changes, it works like a dream.
One little caveat for our good friend IE7: You still need to do that left:0 property. Every single time. Otherwise, it pretends you didn’t really mean to position that element at all. You were only joking, right? Oh, IE7, you do seem to have an extra special sense of humor.
Really, though, it is that easy. It involves very minimal IE6-specific styling and works great for everybody else. This can be used for navigation elements, headings, logos, and more.
When I discovered this little trick, I just assumed people had done it before, and I was just late to the game. However after asking around, apparently this isn’t a widely used idea, so I humbly submit Backslider to the internet.
Have a better idea, hate the name “Backslider”, or just want to set me straight? Send me a note. Thanks!