1304Days

1304 days since this post was last revised. Specific details are likely out of date.

It’s a common requirement to use an image sprite as a background image. The technique has the benefit of utilising a single graphic for a multitude of UI purposes. However, when zooming a page that uses an image-sprite for the
background-image of visual elements, visual havoc can ensue with very different results cross-browser.

When I first wrote this post I literally thought that browsers weren’t attempting to scale background-images when a user zoomed. I reached out to Tab Atkins, he of Google and W3C spec writing fame, to ask if there was any value in a background-zoom property. He kindly pointed out (without stating the bleeding obvious – that I was merely a buffoon) that I was merely seeing pixel rounding errors? What? You again?

The problem is that all the browsers behave differently. From a CSS authoring point of view, the correct part of the image sprite is shown in the desired place by altering the background-position property. The position itself can be set with a number of values, such as px, em, rem and %. All well and good – for the most part. Take a look at this page: http://cdpn.io/Cctvl. Alternatively, here’s an embed:

See the Pen Positioning backgrounds with rem,em,% and px by Ben Frain (@benfrain) on CodePen.

Just don’t zoom the page!

If you look at that on different browsers you can see how inconsistent they are. Whatever, unit (px, %, em, rem) is used, at the time of writing this, only Firefox gets things right (most come back into line at 150% zoom but between 100% and 150% it looks awful). Chrome is worst and Safari is somewhere in the middle (fixed now in WebKit core: see the boxed section below).

Percentage based positioning is arguably the best compromise but that is problematic in general. Consider an image sprite with the intended image 75% along the sprite. By specifying a background position of 75% not only is background ‘start point’ 75% but also the position the background-image begins in the box it is applying that background to is 75% also. What, what in the what what? Yes, that’s right. This accounts for the common frustration many CSS authors experience when trying to position background elements using percentages.

Ordinarily this percentage based positioning system makes perfect sense. If you’re not using an image sprite, writing background-position: 50% 50%; means an background image is positioned 50% along each axis and positioned 50% in each axis of the box it sits within; simple centring.

An additional problem often reveals itself when working with image-sprites and setting background-position in percentages. Let’s suppose we create an image sprite with 10 elements and as an author we position each using percentages. If at some point in the future we want to add another image to the sprite, suddenly all our percentage calculations need re-computing (the item that was 75% along the image sprite is no longer 75% along the image sprite).

A solution for zoom-able sprites? Back to data-uri?

I don’t have a solution to offer you at present. But I’ll be happy if someone knows a consistent way to do this?

I’ve added my voice to the bug trackers of Chromium and Safari:
WebKit Bugzilla 125118
Chromium bug 264863
Update: the issue has been fixed in WebKit now (see link above) so should be fixed in a future Safari release.

At present, this difficulty in implementation is one more reason why, despite that in many ways I consider image-sprites the ‘gold standard’, my pragmatic side would consider opting for using a data-uri for each needed image over an image-sprite (as shown in the last example of the CodePen). That way it would be possible to set a background-size and background position of 50% 50% and you’d be done!

Ben Frain Developer, Author: 'Enduring CSS', 'Responsive Web Design with HTML5 & CSS3'.