The new Apple IPad (IPad 3) came out on the 16th, and probably the first thing I noticed about it is how great the screen looks. It’s armed with same “retina” display that the IPhone 4 came out with a few years ago. It’s great! Except for one thing- a lot of images on the web look like crap now!
(This first image is the standard resolution, the second is optimized for IPhone 4 and IPad 3 screens)
Now- this isn’t new. The IPhone 4 has the same “quirk”, but I think it’s less noticeable given the the size of it’s screen. It really stands out on the IPad 3’s 9.7 inch screen.
The Problem with Pixels
With the advent of high pixel density displays, the pixel itself is now a relative unit.
According to the CSS 2.1 Spec:
Pixel units are relative to the resolution of the viewing device, i.e., most often a computer display. If the pixel density of the output device is very different from that of a typical computer display, the user agent should rescale pixel values.
So, a CSS “pixel” indicates one point on the “virtual” pixel grid to which your CSS design aligns. This either directly matches the actual device, or it is “somehow” scaled to suite.
Talking about the new IPad 3 specifically, the new retina display has a huge 2048 x 1536 pixel resolution- double what most sites are designed for. On a desktop machine, if you doubled your screen resolution, websites would just show up half as big. But on the IPad 3, it stretches the site so it “fills up” the screen. The problem with this is stretching raster images (gif, png, jpeg’s) can make them look really distorted and full of artifacts.
So- how do you fix this?
The easiest way to fix this is to make a second copy of all your images at double the resolution, and then use these versions when visitors are on an IPad or IPhone (or any device that has a higher pixel density).
Fixing it in CSS
The min-device-pixel-ratio media query can be used to target style for high pixel density displays. For the moment vendor prefixes are required, until there is a standard format. For example, Mozilla and Webkit prefixes work the same way, but Opera requires the pixel ratio as a fraction.
-moz-min-device-pixel-ratio: 2 -o-min-device-pixel-ratio: 2/1 -webkit-min-device-pixel-ratio: 2 min-device-pixel-ratio: 2
Right now, we only care about IPhone/IPad, so we’ll use the -webkit-min-device-pixel-ratio tag.
So let’s say you had a single class, loading the 300 x 300 px image:
.logo { background-image: url(cat_300.jpg); width: 300px; height: 300px; }
You would then create a second copy of the image at 600 x 600 px resolution, and add this in your CSS:
@media only screen and (-webkit-min-device-pixel-ratio: 2) { .logo { background-image: url(cat_600.jpg); background-size: 300px 300px; } }
This loads the 600 x 600 px image, but forces the background-size to 300 x 300 px when the device is a webkit device, and the pixel ratio is 2.
Forcing the 600 x 600 px image into a 300 x 300 px box, forces the image to a pixel density of 2.
Fixing Inline Images
So that’s CSS- what about plain old <img> tags?
You can use the window.devicePixelRatio property in JavaScript to determine if the pixel density of the screen is > 1 and if so, cycle through all the images on the page and change their image src to the higher resolution image.
An easy way to do this is to add a class to all the images you want to replace. In this case, I’ve added the “hd” class to the image tags.
<img src="cat_300.jpg" width="300" height="300" class="hd" />
Then add some simple JavaScript to update the tags. In my example, I’ve used jQuery just to make things easier, and simply did a text replace in the src image name, changing the “300” to a 600″. The width/height of the <img> tag needs to stay at 300 x 300 px, forcing the pixel density of 2.
$(document).ready(function() { if ( (window.devicePixelRatio) && (window.devicePixelRatio >= 2) ) { var images = $('img.hd'); for(var i=0; i<images.length; i++) { images.eq(i).attr('src', images.eq(i).attr('src').replace('300', '600')) } } });
Now, there are all sorts of ways to do this- this is just one example.
The other way to do this is to just always load the higher resolution images. The only downside, is those higher resolution images are likely almost twice the size of their originals- so loading them only when required will save bandwidth.
What about SVG?
SVG (Scalable Vector Graphics) is also another great way to handle this. SVG files are actually XML files that have instructions on how to “draw” the image on a canvas, rather than using a static raster image. SVG files can scale to different sizes/pixel densities, without distorting.
The only downsides with SVG, is that sometimes the file size for complex images are actually a lot bigger than their raster counterparts, and browser support is still incomplete- so if you care about your site working in Internet Explorer, then you still need to have some raster images and do conditional loading.
Parting Thoughts
Remember- you don’t *actually* need to do any of this; a lot of images will still look “fine” being stretched.
But if you want your site to look it’s best, it’s worth spending the time to optimize it for higher pixel density devices- there’s going to be no shortage of them in the coming years!
HEy Mike, thanks for the post. Interesting stuff. I was able to get the .css version working but not the javascript for some reason… its not finding and changing the image source. Can you take a peek at it please.
Here’s the site:
http://www.tinsley.com/ipad/index.html
I have this in the body:
This in the script:
$(document).ready(function()
{
if ( (window.devicePixelRatio) && (window.devicePixelRatio >= 2) )
{
var images = $(‘img.hd’);
for(var i=0; i < images.length; i++)
{
images.eq(i).attr('src', images.eq(i).attr('src').replace('300', '600'))
}
}
});
It was your jquery was messed up. Used this and it worked
Glad it works Gio,
I’m not sure what the deal with the WordPress jQuery instance is; I tend to use the google apis hosted version.
Cheers,
Mike
In addition to using:
@media only screen and (-webkit-min-device-pixel-ratio: 2)
I’d suggest you add in:
@media only screen and (-webkit-min-device-pixel-ratio: 2) and (min-device-width: 768px)
While the iPhone 4 has a Retina display, most images are already shrunk down since the webpage is shrunk down on first view on the iPhone. The higher image quality won’t be evident. On the iPad, the webpage size is 1:1 ratio so the Retina images are visible.
Thanks Nathar,
You’re correct in that it’s definitely more evident on a iPad than and iPhone, but you can still see a fairly obvious difference when comparing a 1 vs 2 pixel dense image on an iPhone- especially if you zoom in on the page.
Mike
Not worth the development effort and resulting complexity in my opinion. Goes against good web development practices. Maybe ok for non-serious one-off pages and individual projects, but as a site-wide strategy for anything serious, I’d be questioning the need to influence images on the page with JS just for one device. The impact on site maintenance, content preparation, and potential conflicts with existing functionality, it’s not ideal at all. Images look fine as is on iPads and retina phones. Please don’t promote a web where developers need to use 1990s browser sniffing and branching at the image level! That’s not cool.
I agree that it’s going to be a pain in the ass for web development; and any half-way decent web developer is going to do this is CSS and not in JS (which in my op. is a really bad solution vs. the CSS changes)- but this isn’t just for one device- right now the iPhone4, 4s, iPod, iPad, the new Mac book pro that just came out two weeks ago, and the new Asus Prime Android tablet that goes on sale next month, all use high-density displays. Also LG is talking about making “retina” displays for desktops.
If you’re fine with giving a poorer experience (and it is definitely noticeable; I’ve pretty much lived on the new iPad for months, and *most* sites look bad now), then that’s up to you- but I would say this needs to be included in a “serious site-wide strategy”- as there are only going to be more of these displays in the future.
Mike
Where can I download the simple CSS for ipad 3? I need the resolution fixed automatically rather than going through all these steps. queries, replacing images with HD, etc. I tried doing my own CSS with Box size defined in px or percent but is that good?
Do I have to convert all images from 72dpi to 120dpi or higher for ipad 3? You said double it, menaing 144dpi?
Tony,
The fix for CSS is shown in the post- see the “Fixing it in CSS” section.
and you do not need to change the dpi of your images- you just make an image that is twice as wide and twice as high.
For example- if you image has a width of 300px and a height of 200px, you would need a version that is 600px wide and 400px high, and then use the CSS from my post to force the larger image down to 300×200, thus creating the 2 pixel density.
Hope that makes sense,
Mike
Mike,
thanks for the rapid response. So far….(bear with me since I’m not fully understanding the programming part of Dreamweaver). It hasn’t clicked just yet…urghh! I reread your tip, so I take as duplicate images to be uploaded, not one. Whenever someone uses desktop computer, it forces to use 300dpi images. And when the user switches to ipad, the CSS automatically forces to use 600dpi images. Therefore two copies, am I understanding right so far? When you said add to the CSS, do you mean “document only” or it can be external CSS only like “Ipad.CSS” and load it to the document or template?
What is your take one single image in largest resolution upload rather than two separate image resolutions by modifying the “Box” in CSS? for example, I save the png file in 500 px at 144 dpi, this CSS setting is 250px height, auto width. Apply the css to image and it forces to always be at 250 px and the resolution is always set to highest in any devices, ipad, destop, etc.. Overdone or illogical? Thanks.
Hey Tony,
I haven’t really used dreamweaver, so I’m not really sure where to go to make changes- but try to forget about dpi- that’s only really relevant when you’re printing.
What I mean, literally, is if you have an image that’s say 100px wide X 200px high, then you would so make a version that’s “twice” as big- so 200px wide X 400px high.
Then in CSS (however you get to it in dreamweaver), you would load the 100×200 version by default, but load the 200×400 version on 2px dense screens (like the ipad3), but force that image back to 100×200.
So the image still only consumes 100×200 pixels visually on the screen, but because you’ve forced an image that’s twice as big, into half the space, it ends up using a pixel density of 2, giving you the better picture quality.
In my post example, for 2 pixel dense screens, I override the .logo class to load the bigger image (600×600), as well as force the size back down to 300×300 with the background-size CSS tag.
Mike