CSS: Using Percentages in Background-Image
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.