Here is the idea behind the Viewport Cookies:
- first, detect the width of the device viewport using javascript and store its value in a
viewport
cookie from within the<head>
; - use that cookie in the backend (with Nginx
image_filter
or a PHP script) to resize, cache and serve images of appropriate size for that particular viewport.
The great thing about this method is that it doesn’t require any modifications to the image tags and the javascript is kept to the bare minimum.
Part 1: Store the Screen Width in a Cookie Using Javascript
Javascript is the only thing that can detect parameters such as browser window dimensions and device screen size, so we have to use javascript until (and if) browsers start setting this data in HTTP request headers.
Cookies, however, are the only dynamic thing that can be passed together with the request to the backend without changing the request URL. So we use them both to first choose an optimal reduced image width and then store it into a cookie called viewport
which the browser will send along all the subsequent requests, including for the images.
Keep in mind that cookies are set per domain name and in case you’re of using a Content Delivery Nework for serving static assets you will have to set the viewport
cookie from the CDN.
<script type="text/javascript"> if (screen.width < 1000) viewport = 800; if (screen.width < 800) viewport = 600; if (screen.width < 450) viewport = 400; if (typeof viewport != 'undefined') document.cookie = 'viewport=' + viewport; </script>
You can use whatever logic and levels of adaptiveness you want, but keep in mind that not setting a viewport cookie for larger screens will save you cache hits.
Here is a simple filter for WordPress that will put it into your theme’s <head>
:
add_action( 'wp_head', 'add_viewport_cookie_js' ); function add_viewport_cookie_js() { ?> <script type="text/javascript"> if (screen.width < 1000) viewport = 800; if (screen.width < 800) viewport = 600; if (screen.width < 450) viewport = 400; if (viewport) document.cookie = 'viewport=' + viewport; </script> <?php }
Part 2: Use the Viewport Cookie Value to Serve Resized Images
Once the cookie is set, it will be passed along all the subsequent requests, including for images, so we just read it’s value in the backend and resize the image accordingly. Here is an example of how to do it in Nginx:
location ~ \.(jpg|jpeg|gif|png)$ { expires max; # Resize only if a valid cookie value is present if ( $cookie_viewport ~ ^800|600|400$ ) { return 418; } error_page 418 = @viewport_image; } location @viewport_image { internal; expires max; add_header X-Viewport $cookie_viewport; image_filter resize $cookie_viewport -; image_filter_jpeg_quality 90; error_page 415 = /empty; } location = /empty { internal; empty_gif; }
In the first location block that captures all images we simply add a new check for a valid value of the viewport cookie. If a valid cookie is present, we send the request to an internal virtual location called @viewport_images
which uses the built-in image_filter
function of Nginx to resize the image accordingly. Notice that we are specifying only the width of the image while the height is set to -
, which means that it will be scaled proportionally.
We also add a custom HTTP header called X-Viewport
to make it easier to verify the viewport size that was used in the backend (via the Network tab in Developers Tools, for example).
Conclusion
Viewport Cookies is an extremely simple method for serving images of reduced dimension and file size to devices and browser that can display only a certain amount of pixels. Although the screen size of a device doesn’t necessarily mean that it has a slow network connection (like when using iPad on a WiFi network vs GPRS), it is still beneficial to browser that have screens smaller than SVGA (800 x 600).
Seriously cool.
I imagine the occasional person would have a poor experience if they had their browser window really small when they loaded your site, then expanded it to regular width afterwards. You could possibly pass the device type along as well (I assume you can access that via JS), but I’m not sure it’s necessary for the rare occasion that problem cropped up.
Ryan, notice that the script is actually using the screen width (not window width) so resizing browser wouldn’t have any affect.
Oh, awesome! Well it seems you thought of everything :)
Nice :) It’s like http://adaptive-images.com but without the image generation features. And likely a lot faster than AI as it doesn’t need PHP.
Even screen width isn’t fixed though. Think tablet or phone swapped from portrait to landscape ….
Screen width is always based on the landscape mode on a mobile device. The browser width is used for the portait mode.
I just looked up HTTP status code 418 as I wasn’t sure what it was. It’s now my favourite status code.
I didn’t know what it stands for too, John :)