Ogre Codes

Follow @ogre_codes to get notified when new articles are posted to this site.

👨🏻‍🎤

Lightning Fast High Quality Images. 👨🏻‍🎤

Jun 23, 2017 at 11:09 PM

I love photography and I love posting and sharing my photos. So when I started building photo support for the blogging app, I knew I had to pull out the stops when it came to quality. The most common way of doing web images on blogs uses a single thumbnail image and a larger image, but the result is either a low quality non-Retina image or a wastefully large on smaller or low resolution displays. On the modern web, you don’t need to make these compromises, you can present a set of images which are the highest possible quality for the display without wasting bandwidth. This is a brief tutorial on using media queries and the relatively new srcset attribute to deliver lightning fast pages with the highest quality images possible.

CSS Media Queries

The primary tool we’re going to use is the CSS media query. A media query is a simple CSS rule which is only active when specific conditions are met. For example if we wanted to toggle between 3 different resolution images based on display size, we could use a set of media queries like this:

CSS C

    .medium { diplay: none }
    .large { display: none }

    @media (min-width: 576px) {
      .small { display: none }
      .medium { display: block }
    }
    @media (min-width: 968px) {
      .medium { display: none }
      .large { display: block }
     }

HTML

<img class="small" src="hello_320.jpg">
<img class="medium" src="hello_640.jpg">
<img class="large" src="hello_960.jpg">

In the above example, we come at the problem with a mobile first approach, the default is showing a small image for small displays. The @media selectors trigger as the screen size gets bigger and disables the smaller images and shows the larger ones progressively as the display gets larger. In this example, I’ve built out the media queries by hand, but our blogging engine uses Bootstrap which includes a comprehensive set of media queries built specifically for this sort of thing.

By using media queries, we can upload the appropriate sized images for any given display size from a smartphone (sub 576 effective pixels) up to the largest displays and every point between.

The SCRSET attribute

While media queries are an effective way of dealing with multiple screen sizes, the results will be a bit dissapointing if you have a higher resolution display. When Apple released their Retina display, they had a problem; if they rendered pages using the actual resolution of the device, images and layout would be proportionally smaller resulting in tiny images and often broken layout. To work around this, they virtualize the pixels on the page, if a web page requested a 100x100 pixel image, they would render it over a 200x200 pixel area so it appeared the same size. The resulting pages appear closer to what the web page authors intended, but if the original image is 100x100, the result is blurry. The quick and dirty work-around to this problem is provide over-sized images for resources. While this is effective, it results in a lot of wasted bandwidth as clients with lowere resolution displays end up pulling down oversized images. Fortunately there is a better solution to this.

The W3C adopted the srcset attribute which allows you to create multiple alternative resources based on the actual display resolution while preserving a single effective pixel size.

<img src="HelloWorld_360.jpg" 
       srcset="HelloWorld_360.jpg 1x,   HelloWorld_720.jpg 2x, HelloWorld_1080.jpg 3x">

Modern web clients will load the 1x, 2x, or 3x image appropriate to the device while older web clients will load the image from the src attribute. The result is your browser loads the highest quality image it’s possible of effectively displaying... which is exactly what we want.

Pulling it all Together

By combining media queries and the SRCSET attribute, we can serve up high quality images which are appropriate for the size and pixel density of the display. In order to do this, we just need to have a series of images on our server of varied sizes. Additionally, we can over-load our sizes, using specific sizes for multiple purposes. For example: a 360 pixel image can be used for a smartphone full sized image and a thumbnail for larger devices; a 720 pixel image can be the 2x image for a smartphone or a medium sized 1x image for a desktop computer; a 1080 pixel image becomes a 3x smartphone image or an extra large 1x image; and so on.

I’ve settled on 5 image sizes from 360 pixels up to 2160 pixels so I have up to 3x resources for smaller displays, 2x resources medium sized displays.

1x2x3x
Thumb3607201080
Small 72014402160
Medium10802160
Large14402160*
Extra Large2160
* Not exactly 2x, just use the largest possible size

We’ll use the same images everywhere we have the same resolution so by producing 5 scaled images we have a lot of flexibility in the displays we support. While there is room for additional image sizes, for example a smaller thumbnail size might make sense, we’re very close to the point of diminishing returns with these 5 sizes.

Wrapping it Up

These two techniques form the basis for the image presentation on the site, the next couple of posts I’ll talk about how the app actually renders these tags intelligently from image resources on the iOS device and how to present full scale images when thumbnails are tapped on the web page.

Sample Gallery