Serving High Res Images to Retina Display

Serving high res images to retina display

Why setting for Retina

iPhone 4s, iPhone 5, iPad3, iPad4, Macbook 15", Macbook 13" all use Retina display.

Android also support high resolution display, as well as Windows 8(Lumia 920) as mentioned by @JamWaffles.

Adding high resolution support is good for user experience but it definitely add load for developer, as well as bandwidth for mobile. Somebody don't suggest doing that.(Peter-Paul Koch, see the bottom "further reading")

Breifing

There are two methods to implement this function. One is Javascript and the other is CSS. All current solutions are for Retina, but could extend to Android high resolution easily.

CSS solution is about Media Query and -webkit-min-device-pixel-ratio or -webkit-device-pixel-ratio

  • Simple to use.
  • Apply to all browsers.
  • Disadvantage: Good for background. Harder for <img> tag

Javascript solution is about window.devicePixelRatio property.

  • Advantage: Javascript could manipulate image source. So, if you are going to serve direct image instead of background, better to use Javascript
  • Could not apply to all browsers but current support is good enough. See below for list.
  • Need a bit more setting.

CSS Solution

For normal images, say an icon

.sample-icon {
background-image: url("../images/sample-icon.png");
background-size: 36px 36px;
}

For Retina, add those below

@media only screen and (-webkit-min-device-pixel-ratio: 2), /* Webkit */
(min-resolution: 192dpi) /* Everyone else */ {
.sample-icon {
background-image: url("../images/sample-icon-highres.png");
background-size: 18px 18px;
}

You can use min-resolution: 2dppx to replace min-resolution: 192dpi, for those who don't want to remember numbers

Note the difference:

  1. Two different icons, one normal, one high res. High res icon is double size than normal one.
  2. The background size. The later is half. But you need test it in your real use.

Resource:
+ http://www.w3.org/blog/CSS/2012/06/14/unprefix-webkit-device-pixel-ratio/
+ http://view.jquerymobile.com/master/demos/widgets/buttons/#CustomIcons

Javascript Solution

Use window.devicePixelRatio property to detect resolution.

if (window.devicePixelRatio >= 2) {
alert("This is a Retina screen");
//Do something to manipulate image url attribute
//for example add `@2x-` before all image urls
}
Browser Support

Safari, Android WebKit, Chrome 22+ and on Android, Opera Mobile, BlackBerry WebKit, QQ, Palm WebKit,
Ref: http://www.quirksmode.org/blog/archives/2012/06/devicepixelrati.html

For Android

Android device use 1.5 as high resolution instead of 2 in Retina.
http://developer.android.com/guide/webapps/targeting.html --#Targeting Device Density with CSS, #Targeting Device Density with JavaScript

Further Good Reading

http://www.quirksmode.org/blog/archives/2012/07/more_about_devi.html
"I’m not a big fan of serving special retina images because it makes the web too heavy — especially over a mobile connection. Nonetheless people will do it." -- Peter-Paul Koch

Update 2013-04-18 Update jQuery mobile link

Retina displays, high-res background images

Do I need to double the size of the .box div to 400px by 400px to
match the new high res background image

No, but you do need to set the background-size property to match the original dimensions:

@media (-webkit-min-device-pixel-ratio: 2), 
(min-resolution: 192dpi) {

.box{
background:url('images/box-bg@2x.png') no-repeat top left;
background-size: 200px 200px;
}
}

EDIT

To add a little more to this answer, here is the retina detection query I tend to use:

@media
only screen and (-webkit-min-device-pixel-ratio: 2),
only screen and ( min--moz-device-pixel-ratio: 2),
only screen and ( -o-min-device-pixel-ratio: 2/1),
only screen and ( min-device-pixel-ratio: 2),
only screen and ( min-resolution: 192dpi),
only screen and ( min-resolution: 2dppx) {

}

- Source

NB. This min--moz-device-pixel-ratio: is not a typo. It is a well documented bug in certain versions of Firefox and should be written like this in order to support older versions (prior to Firefox 16).
- Source


As @LiamNewmarch mentioned in the comments below, you can include the background-size in your shorthand background declaration like so:

.box{
background:url('images/box-bg@2x.png') no-repeat top left / 200px 200px;
}

However, I personally would not advise using the shorthand form as it is not supported in iOS <= 6 or Android making it unreliable in most situations.

CSS for high-resolution images on mobile and retina displays

In your HTML, create a <div> like so:

<div class="ninjas-image"></div>

And in your CSS, add:

.ninjas-image {
background-image: url('ninja-devices.png');
width: 410px;
height: 450px;
}

@media (-webkit-min-device-pixel-ratio: 1.5), (min-resolution: 144dpi) {
.ninjas-image {
background-image: url('ninja-devices@2x.png');
background-size: 410px 450px;
}
}

The magic here is in the CSS @media query. We have a double-sized image (ninja-devices@2x.png) that we sub-in when the device reports a ‘device pixel ratio’ of 1.5 (144 dpi) or more. Doing it this way allows you to save on bandwidth by delivering the original, smaller image to non-retina devices, and of course it looks great on retina devices.

Note:

This answer was updated in 2016 to reflect best-practice. min-device-pixel-ratio did not make it in to the standard. Instead, min-resolution was added to the standard, but desktop and mobile Safari don't support it at the time of writing, (thus the -webkit-min-device-pixel-ratio fallback). You can check the latest information at: http://caniuse.com/#feat=css-media-resolution.

Optimizing website images for Retina display

In the future, you might be able to use the picture element. In the meantime, the only approach I've seen that might work is to:

  1. Put a div or span where you want the image. Style it to have the dimensions and layout of the image. Add some kind of identifying mark to it so you can find it (e.g. class="retina-image")
  2. Store information about the different sizes of images you have on or in the element (e.g. using data-something attributes)
  3. Put a <noscript><img src="..." alt="..."></script> inside the div
  4. On DOM ready:
    1. use JS to find all the elements with the identifier from step 1
    2. detect the type of image you want
    3. find the attribute that tells you what URL to use for that image
    4. add the image to the DOM inside the container from step 1

This is the approach used by the picturefill library.



Related Topics



Leave a reply



Submit