Full service digital agency.

We create awesome digital experiences that make people smile

Get to know us

EN slash NL

Adaptive resources versus responsive design

 About a year ago a new html5 solution for responsive images was introduced in which a srcset and sizes attributes can be added to img elements. A much needed feature in the ever growing world of responsive design. See also this blog by Arthur Stobbelaar. Now, although this adds significant possibilities to the HTML spec I propose an alternative using the HTTP spec.

Because both specs are not aligned srcset and sizes were introduced to move things forward. This means that the browser needs to be supplied with all the information needed to provide the perfect experience. And so, we stuff our CSS and JavaScript files with information for different screensizes, but this does not fly for images since they are dumb and do not contain different sizes in one file. And where CSSfiles are small enough to contain all variants, images would become ridiculously big. As a result we are forced to use HTML to inform the browser about different image sources for it to choose from.

But what if we approach it from the other side. What if we would not supply the browser with all possibilities but instead with the right data when it requests it. We could simply tell the browser the location of the CSS, JavaScript or image and the provider decides what real source is best. In my opinion it seems silly to bring everything to the party when I don’t know what party it is and what the dress code is going to be. When you go to the doctor you don’t bring all possible medicines hoping the doctor will find the right one. And this goes for the internet too. We are forced to use HTML to send all posibilities to the browser. What if could simply tell the sender what it needs.

So, let’s explore the side of the sender, the side where the resource is being hosted. The starting point is the single image source provided to the consumer using the src attribute of the img element. This source is basically arbitrary and might not even exist. It is just a source location which got a whole lot smarter.  This is how.

When we provide different sources in the srcset approach we tend to use image names like photo, photo-highres and photo-lowres.jpg. Basically we use some sort of naming convention to distinguish between the types. So, if that’s the case, why provide them to the browser. We might as well provide the right photo when it is requested. If we know the request for photo.jpg comes from a device with a small screen we could simply send photo-lowres instead. The only problem is that we don’t know what the screen size is. Or do we?

Determining screen sizes on the server is quite an ordeal and although there are amazing regular expressions to unleash on the user-agent it’s simply not bullet proof because the user-agent has no convention. So, if we have no reliable information we need to supply it, but how? There is no way to extend the HTTP header info on image requests and even if we could with JavaScript it would add a lot of overhead. So we need another vehicle that we can set once and will be passed on all subsequent requests. And there is one: Our old friend, the cookie. Loved and despised at the same time it is the ideal vehicle.

Using a cookie we can provide it with the right information about the image we want, being the normal, lowres or highres photo. And to do so we use JavaScript. But hey, you say, that’s overhead! It is, but it is blatantly small and only needs to run once (see code block). All it needs to do is to retrieve the screen size and set a cookie value with the required quality. That’s it, we have filled the vehicle with the appropriate information and it is automatically send in every subsequent request, including images. So all we got to do is to use it on the server.

<script>
if (screen.width <= 480) {
document.cookie = 'imagequality=lowres; path=/; domain=' + window.location.host;}
else 
{
document.cookie = 'imagequality=; path=/; expires=Thu, 01 Jan 1970 00:00:01 GMT; domain=' + window.location.host;
}
</script>

Now, I can imagine you thinking: Hell, I’m not going to build an image handler in all my websites to read the cookie, and find the right image. Well, surprise, you don’t have to, because in comes the url rewriter. In this case I have used the UrlRewriter of IIS but others should work similarly. Using the rewriter we can have it check for cookie information with a regex and use the information in that cookie to alter the request url. So, we check for the cookie ImageQuality and use its value to inject in the file name. In this case the cookie value lowres is injected in the url, making it /photo-lowres.jpg. Here’s the full sample for your web.config.

<rewrite>
<rules>
<rule name="Quality" stopProcessing="false" enabled="true">
<match url="^(.*).(jpeg|jpg|png|gif)$" />
<conditions>
<add input="{HTTP_COOKIE}" pattern="imagequality=(\d+)" />
</conditions>
<action type="Rewrite" url="{R:1}_lowres.{R:2}" appendQueryString="false" />
</rule>
</rules>
</rewrite>

So there we go, using the standard src attribute we now provide the right image for the right client. Simply by using cookie values and rewriting them into the url path or querystring. And, screen size is just one metric. Other metrics could be provided by the client, like dpi or image format. Imagine you could determine the bandwidth or connection type (WiFi, 3G) using JavaScript and send this with the request. With this you could actually send a lowres image to a retina laptop that sits in the jungle on a slow internet connection.

But, are there no caveats? Unfortunately there are, but manageable. First off, it only works with JavaScript and cookies but it just means that if these are turned off they get the default. Fine by me. Second one is a bit more problematic and deals with caching. UrlRewriting for IIS says to work well with IIS output caching but it is something to test well on your caching or CDN platform.  Leaves us with one little caveat: the solution is not really responsive. If you change the size of the browser it won’t automatically retrieve other resources. But honestly, how often do you do this mid-browsing a page. Perhaps if you turn your tablet from portrait to landscape. Well, so be it. You’d have to refresh the page.

Now, this is more then just a sample. It is a different approach, a different separation of concerns. Its an approach that fits the diversity of devices, applications and data transportation types. If the HTTP spec would contain more info we would not even need JavaScript or cookies. Using this approach the original response does not need to supply all possible resources (less server overhead), the browser does not have to sift through all of them (less browser overhead) and the user is provided with the best experience using the least amount of data. And this approach works with other types of resources too…

Check out this package on NuGet for a sample using ImageProcessor to supply images with different quality, DPI or even WebP format if supported by the requester.