Responsive Images in WP 4.4: The last few steps …

In WordPress 4.4 a cool new feature was released – support for responsive images. Within the img tag is now new attributes srcset and sizes included. This functions fully automatically and does not need any configuration. Or does it? For the theme developer or the experienced user there are a few improvements that they can make.

Responsive Images

What do responsive images mean? At first we were satisfied when the size of our images adapted to the the container that they were in:

img {
  height: auto;
  max-width: 100%;
}

In this case we generally load a large images for all of the screen sizes. Additionally to support high resolutions screens (e.g. Retina Display) a 2x larger image then originally needed is used. This practice is called downsampling and increases the pixel density of the image.

You see the problem – the amount of data used especially for smaller, mobile devices is too big. A user who needs to wait too long for a site to load moves on quickly. A better site performance has also become important for site ranking on search engines.

Responsive images is a lot more than a simple change with CSS. It loads the best image site depending on the user screen size for the device they are using.

WordPress 4.4

In the WordPress 4.4 release the RICG Responsive Images plugin was merged into WordPress core. The image markup for images which have an alternative image site are automatically extended with the srcset and sizes attributes. This happens to all of the existing images without needing make any changes to the settings in the admin area.

The two new attributes srcset and sizes are dependent on each other and do not function on their own.

Browser Support

Unfortunately Internet Explorer 11 and lower do not support the new attributes. More on the browser support at caniuse.com. This is not the end of the world as these attributes will just be ignored, when they are not supported. If that is not enough then, you can install the above mentioned plugin which still exists. This will load the Picturefill script to provide support to such browsers.

The srcset attribute

As you for sure know, you can change the three standard WordPress image sizes in the settings. When you upload the image these images sizes are automatically generated and saved on the server. Since WordPress 4.4 there is a new image size with a fixed width of 768px. This image size is not visible in the settings as it cannot be changed.

So what has this got to do with the new attribute? All of the alternative image files with different dimensions are defined within the srcset attribute. These alternative image sizes can be like explained above set in the settings. Additionally is the width of the respective image file in pixels added with the letter “w”. This would look something like this:

srcset="https://example.com/wp-content/uploads/2016/03/image_name-300x169.jpg 300w, 
https://example.com/wp-content/uploads/2016/03/image_name-768x432.jpg 768w, 
https://example.com/wp-content/uploads/2016/03/image_name-1024x576.jpg 1024w"

Additionally to the list of possible image sizes the browser is able to recognize the dimensions of the viewport and the screen resolution.

The browser can decide independently which image size to load from the provided selection.

The sizes attribute

What the browser is still missing is the size of container where the image will be placed. This is achieved with the media queries and the sizes attribute.

The sizes attribute is dependant on the theme design and the used breakpoints. As one attribute does not work without the other WordPress core loads a standard set of size rules. This looks like as follows:

sizes="(max-width: {{image-width}}px) 100vw, {{image-width}}px"

If we for example use a 1200px wide image with the previous template then it would mean that til a maximum viewport width of 1200px the image width would match the viewport width. Once the viewport is wider then 1200px the image will be 1200px wide.

sizes="(max-width: 1200px) 100vw, 1200px"

With these specification a 1200px wide image will be rendered as 1200px when in a 1400px wide viewport. On a device with a viewport of 1400px may the layout not need the full width of the screen any more. Additionally, it is most likely that the content is split in multiple columns. Under these conditions the browser will most likely not choose a smaller image which is listed in srcset due to the standard sizes rules.

Structure and order

  • You can use as many media queries as you need.
  • After the media query follows the calculated width. The width can be defined in vw (for the viewport width) or with px, em, rem. A calculation with the CSS calc() function is also possible.
  • The browser checks the media queries in the order that they are written till one of them matches. The rest afterwards are ignored.
  • The last check does not require a media query as it is the last possible condition.

Theme customisation example using Penguin

Now we want to adapt the output of the sizes to the the themes design. We achieve this using two filter hooks. We use wp_calculate_image_sizes for the images within the content of the posts and pages and wp_get_attachment_image_attributes for the featured images.

I ask myself the following questions:

  1. Which breakpoints does the theme use in the different templates?
  2. How do I calculate the maximum width for the different breakpoints?

For the practical example we are using WPZOO theme Penguin. This feature is included in the 0.2 release.

Content images (wp_calculate_image_sizes)

Breakpoints in index.php, search.php & archive.php

I have made the following calculations for these breakpoints:

(max-width: 599px) calc(100vw - 50px), (max-width: 767px) calc(100vw - 70px), (max-width: 991px) 429px, (max-width: 1199px) 637px, 354px

Breakpoints in single.php

The breakpoints for the single post layout are similar. The differences to the posts pages are:

  • With the viewport 992px or wider the distance (margin) to the post container is 50px instead of 30px.
  • With the viewport 1200px or wider the are only two coloumns instead of three make the content 747 px wide.
(max-width: 599px) calc(100vw - 50px), (max-width: 767px) calc(100vw - 70px), (max-width: 991px) 429px, (max-width: 1199px) 597px, 747px

Breakpoints in page-fullwidth.php

Penguin Gold includes an additional page template page-fullwidth.php. This has no sidebar and displays the content across the whole width.

(max-width: 599px) calc(100vw - 50px), (max-width: 767px) calc(100vw - 70px), (max-width: 991px) 679px, (max-width: 1199px) 839px, 1039px

Function in the functions.php

Thus we have three different layouts. Now we bring this all together is a single function which checks the different conditions and adapts the sizes attribute accordingly.

<?php
function penguin_content_image_sizes_attr($size) {
// Singular posts with sidebar
if ( is_singular() ) {
return '(max-width: 599px) calc(100vw - 50px), (max-width: 767px) calc(100vw - 70px), (max-width: 991px) 429px, (max-width: 1199px) 597px, 747px';
}
// Page full width without sidebar
if ( get_page_template_slug() === 'page-fullwidth.php' ) {
return '(max-width: 599px) calc(100vw - 50px), (max-width: 767px) calc(100vw - 70px), (max-width: 991px) 679px, (max-width: 1199px) 839px, 1039px';
}
// 2 col blog with sidebar
else {
return '(max-width: 599px) calc(100vw - 50px), (max-width: 767px) calc(100vw - 70px), (max-width: 991px) 429px, (max-width: 1199px) 637px, 354px';
}
}
add_filter('wp_calculate_image_sizes', 'penguin_content_image_sizes_attr', 10 , 2);
?>

Featured images (wp_get_attachment_image_attributes)

The sizes attribute for featured images needs to be defined in separate function. The breakpoints are the same as with the content images.

Function in the functions.php

<?php
function penguin_post_thumbnail_sizes_attr( $attr, $attachment, $size ) {
if ( 'Penguin800X400' === $size ) {
$attr['sizes'] = '(max-width: 767px) calc(100vw - 30px), (max-width: 991px) 469px, (max-width: 1199px) 696.5px, 414px';
}
if ( 'Penguin800X400' === $size && ( is_sticky() ) ) {
$attr['sizes'] = '(max-width: 767px) calc(100vw - 30px), (max-width: 991px) 469px, (max-width: 1199px) 696.5px, 846.5px';
}
if ( 'full' === $size && ( is_singular() ) ) {
$attr['sizes'] = '100vw';
}
return $attr;
}
add_filter( 'wp_get_attachment_image_attributes', 'penguin_post_thumbnail_sizes_attr', 10 , 3 );
?>

Testing

Responsive Images Test Chrome Dev Tools

For the testing I use the Chrome Developer Tools. With this I can activate the device mode (1). Under “Elements” is the HTML code of the page shown.

When you move the cursor over the src link or the srcset links a popup window shows (2). Within the size is displayed in which the image is rendered. If the rendered image does not exactly match the sizes attribute then the natural size is shown alongside in brackets.

In case the link under the cursor is not the loaded image then is the loaded source is shown (current src). This version that the browser has chosen from srcset.

Responsive Images Test Chrome Dev Tools Network

Under Network you are able to check which size version of the image was downloaded.

Warning: If the browser has downloaded a larger version of the image before then it will be loaded from the browser cache and is not downloaded again. That is why it is best to deactivate the cache when testing (see pointer).

 


Was I able to help you understand responsive image in WordPress better? Did you find an error? Would you do something different how the solution was implemented for Penguin?

Links & Credits

Here are a few link that helped me to understand the topic better:

The featured image was created using the following sources:

This post has been translated into English by Ulrich