Handling high resolution sprite images with CSS3

The iPhone 4 has introduced a new challenge to web developers due to its retina display using a higher dpi than most devices. What looked sharp in desktop browsers and other lower dpi devices appears blurry and pixelated on the iPhone 4 and potentially other devices which will have higher dpi screens. The current solution is to have two sets of images one for general and one for high dpi screens. You then switch it up using media queries depending on the screens dpi, this has been documented and discussed many times. Let’s try a different approach.

So what’s different?

The difference between my solution and others is mine requires only a single sprite image and doesn’t need a special media query to keep the images looking sharp in higher dpi screens.

The above demo loads a single sprite image containing all my icons needed. This image is saved with everything double the size of what it should be.

How it works

The way I get it to display nicely for both dpi’s is to use the CSS3 background-size property to shrink it down to the correct size. Since the iPhone 4 naturally scales the image up there is no artefacts or blurriness as the image is already the correct size so you don’t need to use the special media query to make it render nicely.

.ico {
    background: url(ico_sprite-32x32.png) -78px 11px no-repeat;
    background-size: 96px auto; /* 192/2 = 96px */
}
 
.echeck      { background-position: -54px -14px; }
.creditcard  { background-position: -30px -38px; }
.cash         { background-position: -4px -62px; }

If your sprite image is 192px wide then you shrink the width to 96px and set the height to auto to keep the correct aspect ratio. Setting the background-position is also halved so if it’s 108px down you set it too -54px to get the correct offset.

See some comparison images.

iPhone 3GS showing high resolution sprite imagesiPhone 4 showing high resolution sprite imagesOpera Mobile 11 with DPI set to 291 showing high resolution sprite images

iPhone 3GS on the left, iPhone 4 in the middle and Opera Mobile 11 with 291 DPI set on the right

There are drawbacks

Of course this isn’t perfect but in the correct situation is a much better solution. If you need to support older browsers or less capable then background-size won’t work, see background-size support. There is also file size being larger since the sprite image is double the resolution the image is roughly 30-50% larger in size than the smaller counterpart if you’re working with a 8bit png.

Short URL: http://cssn.in/ja/034

 

Post filed under: css.

Skip to comment form.

  1. Roll on CSS SVG support!
    You’d be able to create one SVG icon, and use that as the same background image for both display.

    We can only wish. :(

  2. beta says:

    Hmm.. the problem with web-browsing on a iPhone is that you can zoom in, so when you zoom in everything (HTML based) will look perfectly sharp, only the images will look ugly because of the zoomed in pixels.

    Any solution to that?

  3. Ryan Seddon says:

    @Shaun O’Connell

    Well good news, iOS5 supports inline svg so scalabale icons are one step closer.

  4. Well, that’s how we do things here for just some time now at the webviews our iPhone App. I almost never used the Media Query thing to load two different versions of images because that’s too much expenditure if you have more than just a few ones. What I don’t understand is why you make a sprite with so big white-space? Or is that just for training purposes?

  5. Ryan Seddon says:

    @Christian Krammer -

    Awesome good to know other people have come to the same conclusion.

    What I don’t understand is why you make a sprite with so big white-space? Or is that just for training purposes?

    Purely just whipped up a quick demo, depending on the devices needed to be supported I would of used the backgroud-clip property to stop the other icons flowing into view and tightly packed them.

  6. ngryman says:

    I’ve used the same technique for mobile games and it works pretty well :) The only drawback I see is to force downloading a bigger asset for less capable devices.

  7. Yeah – nice to see this. I too have had this problem. Initially, I had a site with a header graphic (company logo), 4 column wide buttons with a graphic background – for portrait and landscape, then a promotion space with 4 carousel images.

    Came to the conclusion the logo had to look sharp on iPhone 4 – doubling it was no real issue, cause being a simple 2 color it was tiny as an 8Bit png. The column wide buttons were updated to use webkit css gradients and rounded corners (duh!).

    However, while your solution could work for all assets, if you have a color rich graphic (i.e. like a photo), not so much. In the case of our carousel – where there are already 4 graphics – making them double the pixel size just wasn’t an option (2xwide x 2xhigh = 4 times larger).

    Cool of you to share – but don’t go mental and make a call on how important the asset is – branding – reused assets – key sections; sure, but not for everything.

  8. Ryan Seddon says:

    @ngryman & @Steven Wright

    Yep I would only recommend this with simple icon based images.

  9. Great idea – this technique is also working great for newer hi-res Android devices

  10. Alex Tsouloftas says:

    Really interesting tutorial. What would you do for IE 8.0 though? Let’s face it, it is the most used browser in U.S and Europe…

  11. Ryan Seddon says:

    @Alex Tsouloftas

    This demo was geared towards usage in smart phone that have rather good support for CSS3 not really that useful for desktops.

  12. Not sure just a pure background-clip would eliminate the whitespace. You’d have to combine with :before or :after pseudo elements, but that would still require some amount of whitespace.