Last week you might have noticed we’re trialling a new experimental screen gadget in our books section — a JavaScript-powered book that allows you to thumb through the book to get a quick sense of the layout and feel.
While I might talk about that directly later, I thought I’d share some of my research on CSS background images along the way.
Like a lot of CSS/JS based animation these days, I used ‘background image sprites‘ — a large background-image containing all the frames, with background-position used to control which frame (or animation cell) is being displayed. Each click moves the background position exactly one frame down. The key advantage to using one image is you can guarantee all frames will be cached the moment your animation is ready.
There are three viable methods available to control background-position, and you are not allowed mix and match them (i.e. background-position: top 50%;).
1) Keywords : i.e. background-position: top right
Keywords are probably the most commonly used method, because they are really easy to get your head around and they work totally reliably on all browsers. You don’t even had to worry about their ordering — ‘top right’ works just as well as ‘right top’.
The main down side to keyword positioning is their lack of granularity. Three vertical (top, center, bottom) and three horizontal (left, center, right) gives you an absolute maximum of nine frame positions. There can be no ‘top centerish‘ or ‘right and a bit‘. Additionally, keywords can’t easily be manipulated mathematically like the other two numerical positioning methods.
2) Pixels : i.e. background-position: 0px 0px
Pixel positioning is currently probably the most useful method available. Firstly, the concept is easy to understand. Once we know we are always measuring from the top left corner of both the container and the image, it isn’t hard to predict exactly where a graphic will appear before it renders.
Pixels also lend themselves nicely to be manipulated by maths. In fact, if you have a looping animation (like the book animation), you can let your sprite graphic tile and simply move your background one ‘frame height’ each cycle. When the animation reaches the last frame, the tiling will automatically present the first frame and the loop automatically begins again.
3) Percentages : i.e. background-position: 80% 50%
Percentages are great in theory, but despite there being some very good explanations of it’s subtleties out there, I get the impression they (percentages) are not well understood. I certainly didn’t.
Percentages appear at first glance to have a lot of promise as they can be manipulated easily with maths and have no practical limits on the number of positions (i.e. frames) they can display. The idea that really got me interested in using them was their ability to allow you to resize your images without having to rewrite all your pixel positioning settings — 20% is 20% regardless of your image dimensions. Theoretically you should be able to give your script an image, tell it how many frames it has, and it will work out the rest.
It all sounded great in theory, but some quick testing confounded me. While 0%, 50% and 100% gave me the equivalents of ‘top’, ‘center’ and ‘right’, percentages like 37%, 61% and 88% seemed to veer around crazily.
The key to understanding percentages in background images is understanding that unlike pixel settings, it’s reference point moves. Any percentage refers to a percentage position on the graphic AND on the containing object.
So, when we set a background image at ‘10% 10%’, we are aligning a point on our graphic 10% across and down from it’s top left corner with a point on our HTML element 10% across and down from it’s top left corner.
I must admit this threw me at first but I drew this diagram to help explain it to myself.
This means in practice, if your graphic is the same size as your HTML element, changing the percentage will make no difference whatsoever. ‘0%’ will be identical to ‘73.5%’ and 100%.
Even when you understand the general concept it’s still not particularly intuitive. What happens if you give something a 150% X-position? It’s harder for most of us to imagine the result.
What about if you have a four frame vertical sprite? What would it’s four Y-positions be?
I started guessing that 25% and 75% must be in the mix, but, as you can see in this test case, the four vertical frame positions are set at thirds — 0%, 33.333%, 66.666% and 100%.
Ok,.. so it’s a little strange, but once you’ve got your head around it, it should be really useful, right?
In theory, yes, but the reality is not so hopeful. Honestly, I’m so bored with whining about IE but this is really crappy.
As far as I can tell, both IE6 and IE7 (presumably earlier versions too) have some kind of rounding error which effectively kills using percentages with this type of sprite-based work. Simple percentages like 0%, 50% and 100% are fully reliable, but ultimately no more useful than top/center/bottom.
More complex percentages appear to be a raffle. The error is small, but more than enough to ruin an animation by forcing it off center — looped animations will multiply this error on each pass. Attempting to predict the error and compensate for it in IE also proved impossible, and I can’t imagine any other solution but to stick with pixel positioning
Suffice to say, very frustrating stuff. Insert ‘rolling my eyes emoticon’ here.
If you liked this blog, share the love:


July 6th, 2007 at 1:48 pm
It may be worth mentioning that percentage and lenth values can be combined, but not with keywords. eg. background-position: 50% 90px is acceptable.
http://www.w3.org/TR/REC-CSS2/colors.html#background-properties
July 7th, 2007 at 1:51 am
Negative percentages in background-images give a very nice effect when resizing the window. You can see some examples on my site. Useless but nice.
(excuses for the shameless selfpromotion, but I think this article is some sort of addition)
July 8th, 2007 at 5:10 am
Great article, thanks ;) Answered a few questions I had on the topic that I had forgotten about.
July 9th, 2007 at 4:00 am
Instead of percentages and keywords, have you tried em’s?
July 9th, 2007 at 10:29 am
I didn’t, but I’m fairly sure they’d work fine. I’m just not sure how useful it is to position your background relative to your text size. Changing your text size would move your background, and off the top of my head, I can’t think of a good reason for wanting that to happen — but there may be one.
July 9th, 2007 at 10:35 am
Agreed, Vasilis. Not sure how to get a lot of day to day use out of it, but it’s a nice effect.
July 10th, 2007 at 8:20 am
Couldn’t you just add an equal sized “blank” area at the end of your image? That way, the breaks would be 0-25-50-75.
July 10th, 2007 at 11:08 am
Yes, in simple terms, you could, Bill.
It gets a little bit messy and less flexible, but it should work.
The problems are you have to make all animations to a particular frame counts (i.e 3 frame animations are fine but all 4 frame animations become 5 frame, etc), then manually generate extra ‘padding frames’ when needed, and then have the script adjust so as not to display those blank frames when they exist.
Not undoable — the script could predict if there will be a rounding error, assume you added the padding frame to the graphic, and adjust accordingly — but certainly losing some of it’s natural elegance.
July 10th, 2007 at 11:21 pm
That’s true, Alex. But given the fact that these new blank background areas will result in a single continuous block of pixles of the same color, the impact on the size of the image would be minimal.
Do you have code that generates the images now? If you do, it should be relatively straightforward to start with a blank image of the correct dimensions and “lay in” the real image tiles. If not, the same thing is easy enough to do on creation.
The problem you identify seems to occur with the example you give without my suggestion, by the way. If you add another tile to your background image, you still need to readjust all of the percentages.
As far as coding for it, if you’re going to write a method that generates the CSS classes for you, you could simply add a parameter to the method call that tells it how many blank frames you have. Assume zero if it’s undefined.
July 24th, 2007 at 6:46 am
I something i have been trying to figure out all day, if you know the answer can you please email me poyanp@gmail.com
what i want to to is have sidebox_l_bg.gif (the drop shadow on the right side of the left column repeat-y but i would like it to start 16px below were is does now. Is that possible?? to have a point were the repeat-y begins
#left_col{width:21%;text-align:left;vertical-align:top; background-position: 16px 0 0 0;background-image:#ffffff url(images/colum_top_bg.jpg) repeat-y;padding-top:16px;background:url(images/sidebox_l_bg.gif) repeat-y right; }
chcek it out here
http://www.spadirectory.com
July 24th, 2007 at 11:14 pm
Nice article! But what’s the solution?
I’m having the same problem here. IE7 and IE6 (as always) do not render it correctly… I dont have any idea on how to solve this problem. I’ve already tried using EMs instead of percentage, and it worked. But when the user resizes the window, it ruins the background again.. =( Very sad…
Microsoft should review their own concepts and make an effort to correct all mistakes and give some attention to this, doing warned automatically updates!
July 26th, 2007 at 10:36 am
Renato, using pixels is the only foolproof method. You can probably (not fully tested) use percentages as long as the percentages you use are whole numbers. So three frame animations are fine (0%, 50%, 100).
Four frame animations are no good (0%, 33.333%, 66.666%, 100%).
Five frame should be ok (0%, 25%, 50%, 75%, 100%).
Six frame no good, etc,..
July 28th, 2007 at 1:27 am
I’ve had reasonable success using multiples of -100%. This shifts the background by multiples of the width or height of the containing element. I’ve set up a basic example demonstrating a resizable graphical border using only 2 sprite images (one horizontal, one vertical) and very clean HTML+CSS. The bottom-right corner is a resize handle (using jQuery). I’m working this into a set of tutorials so it’s half-finished.
There was a weird problem with the right and bottom borders; for some reason the effect of the background-position wrapped round at -100% so the background disappeared completely (unless repeat was specified for both axes but there are other reasons I didn’t want this!). I think it’s to do with the left:100% and top:100% positioning of those elements, in combination with the quirks of background positioning as described here. I worked around it by offsetting +100% instead which shifted onto the LAST sprite.
I’ve tested on IE6+7, FF, Opera9, Safari3, all fine.
July 28th, 2007 at 11:01 pm
That was only true in css2 but css2.1 allows for keywords to be mixed and matched with percentages or pixels etc. It is prefectly valid to do this but some older browsers are still confused by it so its still best not to mix keywords into the mix. There really is no point anyway as the keywords equate exactly into eqivalent percentage sizes anyway.