When we overhauled the system that we use to deliver content on devices, one decision we made was to favor HTML5 and CSS3 over “native” components wherever possible. Native components have their benefits — they tend to have better performance than an HTML5 counterpart — but there’s an enormous tradeoff for that performance: a component that works on iOS absolutely will not work on Android or another operating system. Going native means duplication of effort, both in development and maintenance. It also means that expanding to any new platform requires developing a new native component.
One example of where we opted for an HTML5/CSS3 solution was with our image gallery. The original version of our content delivery system used a native component; in the new system, we use the iScroll library to create swipe-able image galleries. When you click on one of the images in a gallery, you get a full-screen view of the image, where you can “pinch” the image to zoom in or out if your device has multi-touch support.
The iScroll library provides a lot of power, but one thing we were never happy with was the image quality when you zoomed in on an image, because iScroll didn’t do anything to redraw the image when it zoomed. That meant that if you zoomed in to 3x on an image that was initially displayed at 320 x 200 pixels, the image ended up looking grainy — each pixel was being displayed at three times its normal size:

More often than not, though, we had more pixel data available to us than we were using to initially display the image — we’d display an image at 320 x 200 pixels to fit the whole image into the space available on a phone screen, but the image stored on the device was actually much larger. It was clear that a better experience should be possible.
Last week, we decided to see if we could improve the zooming situation a bit — one of our clients was working on an app that featured a lot of images with text in them, so there was new urgency to the issue. After a bit of thinking, we realized that the answer was to get the image to redraw at a new size when a user finished zooming, much like Google Maps draws a new set of map tiles at an appropriate scale when you zoom in or out.
Once we had a strategy in mind, the path was pretty clear: we asked iScroll to tell us when the user was done zooming, and then used information about the just-completed pinch gesture to calculate a new image size in JavaScript. A nasty bug in Mobile Safari means we use CSS backgrounds to display most of the images in the app, and that approach made this task easy: we just needed to resize the container the image was in, and -webkit-background-size: contain would take care of the rest. In the end, a lot of thought and a few lines of code solved a nagging problem:
var scale = scroller.scale,
oldWidth = dojo.style(imageContainer, 'width'),
oldHeight = dojo.style(imageContainer, 'height'),
newWidth = oldWidth * scale,
newHeight = oldHeight * scale,
ratio = oldWidth / oldHeight;
dojo.style(imageContainer, 'width', newWidth + 'px');
dojo.style(imageContainer, 'height', newHeight + 'px');
scroller.zoom(scroller.x, scroller.y, 1, 0);
Now that this code is in production, new apps are doing this little bit of math whenever you zoom in on an image in an image gallery, and the change in quality is hard to miss:

We hope you like it :)