Responsive images make websites look better by displaying sharper images on large and small screens. And they make websites load faster by sending the ideal image size to every device type. That’s good for viewers, clients and Search Engine Optimization, as Google uses page load speed as a ranking factor. You can should use responsive images for all websites, and for WordPress websites, it’s especially easy as responsive images are built in to the WordPress content management system automatically.

diagram from US patent 1,867,377 depicting otto rohwedder's 1928 patent for the bread slicing machineA bit of history – sliced bread was invented in 1928 by Otto Frederick Rohwedder of Davenport, Iowa. He was so convinced that he could make a machine to slice a loaf of bread all at once that he sold his jewelry business to fund the cause. He made an early prototype of a bread slicing machine, but it was destroyed in a fire. It took him 16 years to get the the machine finished. The first actual slice of sliced bread was sold on July 7th 1928. Think that was a long time ago?

Responsive images were introduced into the WordPress core waaaaaaaaaaay back in 2015 – December 8 to be exact – in the release of WordPress version 4.4, named for jazz musician Clifford Brown. Since it’s a well known fact that internet time is exactly 20.26x regular time, responsive images were invented just days after sliced bread, which makes them clearly the greatest thing since.

Take a look at the Merge Proposal that pushed responsive images into the WordPress core to find out why this technology was included in WordPress:

8:57 am, September 30, 2015

As of today, the average web page currently weighs over 2 MB with the majority of those bytes being attributed to images. Screen density and display sizes continue to increase and site owners are including larger image assets to keep up, causing slower page load times for people on smaller/older devices and on slower/expensive network connections. We have the opportunity to make a huge impact on the ~25% of the web that runs on WordPress by adding responsive image support out of the box so sites can serve appropriate sizes images to all users.

Those reasons have only become more pressing. So what are responsive images, how do they work and how can we use them to be better web developers to make faster websites that rank higher on search engines? Let’s get into it.

example of responsive images shown in WordPress shown on three different screen sizes - mobile, tablet and desktop

Table of contents

What are responsive images?

Before responsive images, you’d include an image on a web page with the trusty <img> tag. Or maybe you’d include a CSS background image, especially for those big full width banners. You’d size that image as best you could based on how large you knew thought it was going to display. But then websites got responsive, devices bred like rabbits and many of them had incomprehensibly high resolutions. So you’d maybe include the highest resolution image possible and hope for the best. Better than clients calling you saying images looked fuzzy.

Including too-big-to-fail images leads to slow page loads, especially on mobile. Think about it – a giant 2,000 pixel wide image is needed to fill a full width banner for a large screen. But sending that same image to a phone just doesn’t make sense. There’s got to be a better way.

By adding two attributes to the <img> tag, a whole range of image can be be shown to the viewer – a large high resolution image size for large high resolution displays and a small, low resolution image size for mobile phones as well as everything in between. No fuzzy images, and no slow page loads. You don’t even have to do a lot of math. World peace.

Responsive images can send a large, high resolution image to a large high resolution monitor and a small, low resolution image to an older smaller phone. Things look crisp on both and each device downloads the image size it needs. Bam!

How do they work?

Here’s where responsive images are really very cool. The exact moment a web page is loaded – even before the CSS and JavaScript have begun to parse – you know two things and the browser knows two things. The things you know, the browser doesn’t. The things the browser knows, you don’t. But if you put those things together, magic happens.

Things the browser knows
Things you know

How big the viewer’s screen is!

What size the images on the sever are!
srcset

The resolution of the viewer’s screen!

How big the image should appear!
sizes

You put the images on the server, so you know how big they are. And you made the website, so you know how big the images should appear. The browser knows none of that because it hasn’t started loading images or CSS yet.

The browser knows exactly how wide the viewer’s screen is and what the screen’s resolution is. You would have no idea about that because you’re not in the room.

All you need to do is tell the browser two things it doesn’t know – srcset and sizes – and the browser uses that missing information along with what it knows and it then does crazy voodoo lots of math to pick the exact image size the viewer needs, nothing more and nothing less. If that doesn’t make you happy, you haven’t used the web for long enough.

The magic of responsive images happens before the browser has started the heavy lifting of loading images and CSS. That’s the whole point. Reduce the file size of images loaded by telling the browser what it needs to know before it starts loading images and CSS.

How to use responsive images

To use responsive images, you modify the <img> tag by adding the srcset and sizes attributes along with the src and alt attributes that were already there.

Before:

<img src="https://awesome.com/some/path/to/your/800px-wide-image.jpg" alt="an awesome image">

After:

<img 
srcset="https://awesome.com/some/path/to/your/200px-wide-image.jpg 200w,
https://awesome.com/some/path/to/your/400px-wide-image.jpg 400w,
https://awesome.com/some/path/to/your/800px-wide-image.jpg 800w,
https://awesome.com/some/path/to/your/1600px-wide-image.jpg 1600w,
https://awesome.com/some/path/to/your/2400px-wide-image.jpg 2400w"
sizes="(min-width: 1200px) 1140px, (min-width: 992px) 940px, (min-width: 768px) 720px, (min-width: 576px) 510px, calc(100vw - 30px)"
src="https://awesome.com/some/path/to/your/800px-wide-image.jpg" 
alt="an awesome image">

That may look like a lot more HTML markup, but compared to the advantages, it’s a small price to pay. And WordPress generates a lot almost all of that for you.

With the srcset attribute, you list all the image size variants the browser can pick from and you tell the browser how wide each image is. In a non WordPress environment, you’d either make all these image size variants by hand or use a cool service like this one to automate it. You’ll have to make size variants for the smallest size on the smallest screen and the biggest size on the biggest screen and a number of size variants in between. WordPress fully automates the creation of the different image size variants, and WordPress generates the srcset attribute for you.

With the sizes attribute, you tell the browser how wide the image appears. Sure, the browser will figure that out eventually after it has loaded and parsed the CSS. The browser needs to know that information now in order to know which image to send to the viewer – by the time it gets to the CSS, it’s too late.

The sizes attribute looks a lot like a CSS media query. You can use mid-width or max-width and you can use calc() functions. You need to write out the widths listed in the sizes attribute for almost all circumstances because you’re the one who made the layout and computer robots aren’t smart enough yet to figure this out for you. WordPress will spit out a default sizes attribute that is better than nothing, but it’s not ideal unless you modify it to be specific about the display width of each image. Examples of how to do that below.

The example above is telling the browser that for viewports 1200 pixels and wider, the image is 1140 pixels wide, then for viewports 992 pixels and wider, the image is 940 pixels wide, then for viewports 768 pixels and wider, the image is 720 pixels wide, then for viewports 576 pixels and wider, the image is 510 pixels wide, then for all other widths, the image is 100% of the viewport width minus 30 pixels.

The src is included as a fallback and for browsers that don’t support srcset and sizes. Most all good modern browsers do, with the exception of crap like Internet Explorer.

The alt attribute is included the same as ever.

So that’s it. Build out some demo layouts and inspect element in Chrome or Safari dev tools. By selecting the image, you can see which image size variant the browser is currently showing. You can also load up websites using responsive images in Google’s PageSpeed Insights and if you’ve done your job properly, you won’t see any warnings about needing to re-size images. In the words of Borat, “Great Success!”

If you’re hand coding websites, then you’re all done – use the responsive image method as listed above and sail on into the sunset with the winds of fame and wealth at your back. If you’re using WordPress, there’s some fun tricks to get WordPress to help you along the way.

To find out the dimensions of your browser on any device, head to What’s My Viewport Size? and to find out the pixel density / resolution, head to Device Pixel Density Tests.

How to modify WordPress default settings

So responsive images are awesome and WordPress makes them even more awesome. Since WordPress is a content management system, it does a great job of automatically generating different size versions of every image you upload. Those different sizes are automatically listed in the srcset attribute. Score one for making life easier.

WordPress’s implementation of responsive images, however, leaves two main issues for you as a developer to modify if you really want to see the most benefit to page load speed and user experience:

  1. WordPress automatically generates a small handful of image sizes for inclusion in the srcset attribute – including a new size added just for responsive images – but these default out-of-the-box sizes just aren’t enough to get the most benefit out of responsive images in WordPress, particularly for larger full-width displays. You’ll need to modify your functions.php to add additional image sizes based on your website’s display needs
  2. WordPress automatically spits out a default image size for the sizes attribute. While better than nothing, this default size isn’t ideal for nearly all image displays. You’ll need to use one of a few methods to add a detailed sizes attribute to get the most benefit out of responsive images in WordPress

Let’s get into solutions for both.

Increase the number of image sizes WordPress automatically generates

Each time you upload an image to the Media manager in WordPress, multiple versions of the image are created. Without modification, WordPress will make these versions:

  • Thumbnail – a square crop 150 pixels wide by 150 pixels high – called with the_post_thumbnail('thumbnail');
  • Medium – uncropped and resized so the longest side is 300 pixels wide or high – called with the_post_thumbnail('medium');
  • Medium Large – uncropped and resized to 1024 pixels wide – called with the_post_thumbnail('medium_large');
  • Large – uncropped and resized so the longest side is 1024 pixels wide or high – called with the_post_thumbnail('large');
  • Full – original image uncropped and not resized – called with the_post_thumbnail('full');

That’s just not enough sizes to cover modern image needs. A full width image like the top banner on this blog spans the width of all browser windows, and even on a midline laptop, that can be 1,500 pixels wide. At a screen density of 2.0, that’s 3,000 pixels – much more than the stock 1024 pixel wide “large” image size that WordPress creates. In addition to adding larger image sizes, think about any other missing image sizes you may need to display your images.

To add new images sizes, use the add_image_size(); function within the after_setup_theme hook and then give them a name using the image_size_names_choose hook:

/* ADD CUSTOM IMAGE SIZES FOR POST FEATURED IMAGE
================================================== */

add_theme_support( 'post-thumbnails' );

add_action( 'after_setup_theme', 'aw_custom_add_image_sizes' );
function aw_custom_add_image_sizes() {
    add_image_size( 'small', 300, 9999 ); // 300px wide unlimited height
    add_image_size( 'medium-small', 450, 9999 ); // 300px wide unlimited height
    add_image_size( 'xl', 1200, 9999 ); // 1200px wide unlimited height
    add_image_size( 'xxl', 2000, 9999 ); // 2000px wide unlimited height
    add_image_size( 'xxxl', 3000, 9999 ); // 3000px wide unlimited height
    add_image_size( 'portfolio_full', 9999, 900 ); // 900px tall unlimited width

}

add_filter( 'image_size_names_choose', 'aw_custom_add_image_size_names' );
function aw_custom_add_image_size_names( $sizes ) {
  return array_merge( $sizes, array(
    'small' => __( 'Small' ),
    'medium-small' => __( 'Medium Small' ),
    'xl' => __( 'Extra Large' ),
    'xxl' => __( '2x Extra Large' ),
    'xxxl' => __( '3x Extra Large' ),
    'portfolio_full' => __( 'Portfolio Full Size' ),
  ) );
}

You’ll need to upload your images again after adding these to your functions.php in order to generate the additional image sizes, or use a plugin to regenerate all image sizes. So it’s a good idea to do this towards the beginning of your development after a bit of testing but before uploading all your images.

Once functions like the above are added, you should see the additional sizes added in the srcset attribute, and you don’t need to do much else in this department.

It’s worth noting that WordPress will automatically add to the srcset all size versions of the image that are exactly the same aspect ratio as the image size specified. So generally – unless your original is a square image – the thumbnail image size won’t be added and other specific crop sizes may not be included.

Add accurate image sizes

WordPress – like the browser – doesn’t know what you know about how wide images will appear. You’ll need to specify accurate sizes attribute in order to get the most out of responsive images. This is pretty important. You can add custom image sizes to the srcset until you’re blue in the fingertips, but if you don’t tell the browser how large the image displays, almost none of it matters.

Out of the box, the default sizes attribute that WordPress displays for every image is (max-width: $width px) 100vw, $width px where $width is the width of the image specified.

This default sizes attribute tells the browser that if the viewport is wider than the image size specified, the image is shown at the width of the image specified, and if the viewport is narrower than the width specified, the image is 100% of the viewport width. This just isn’t accurate except for a very few circumstances. But WordPress has no idea how wide the image is to be displayed – you have to declare this manually with the sizes attribute. If you take away nothing else from this blog post, you need to properly declare the sizes attribute in order to get meaningful results from the responsive image technique.

There are a few methods for fully declaring the sizes attribute:

  1. Declare the sizes attribute inline in each instance of each image displayed
  2. Declare the sizes attribute for each image in each template
  3. Declare the sizes attribute globally for specific image sizes

As with most anything in WordPress, you can use more than one method.

Method 1 – Declare the sizes attribute inline in each instance of each image displayed

We end up using this method the most, possibly out of habit from manually adding the image srcset in non-WordPress environments. This method is easy as each image is laid out manually whether in a single page or in a template loop that gets applied over and over, so going in and adding a manual srcset attribute for each image isn’t a big deal. The concept here is straightforward – before publishing the website live, make sure each instance of an <img> tag has a properly declared srcset attribute. We normally leave out the srcset attribute entirely during development as layouts change. Once all layouts are approved, before publishing the website, we go back and add in all final srcset attributes based on final layouts, then test them all in Chrome developer tools and in Google PageSpeed Insights.

Here’s the typical code we use

<?php
$image_id = get_post_thumbnail_id();
$img_src = wp_get_attachment_image_url( $image_id, 'large' );
$img_srcset = wp_get_attachment_image_srcset( $image_id, 'full' );
$img_alt = get_post_meta( $image_id, '_wp_attachment_image_alt', true ); ?>
...
<img src="<?php echo esc_attr( $img_src ); ?>" srcset="<?php echo esc_attr( $img_srcset ); ?>" sizes="100vw" alt="<?php echo $img_alt; ?>">

In this case, the image is a large image displayed full width, so the sizes attribute is simple – sizes="100vw". You’ll customize this for each image that’s displayed.

The above code snippet is something we use over and over. We set a variable $image_id to store the image’s id, then use that to generate the src using the wp_get_attachment_image_url() function, the srcset using the wp_get_attachment_image_srcset() function and the alt using the get_post_meta() function.

The wp_get_attachment_image_srcset() function accepts a few parameters, one of which is the size of the image to include as the src. This is handy in that the src attribute is a fallback for browsers that don’t support responsive images, so we generally declare a smaller image size because we figure those browsers probably aren’t used on the highest resolution modern displays so they may not need the giantest fallback image. That’s why you see the 'large' size declared rather than the 'full' size in wp_get_attachment_image_url( $image_id, 'large' );.

Likewise, the wp_get_attachment_image_srcset() function accepts a few parameters, one of which is the largest image size to include in the srcset. We generally declare only the largest size needed for each image because why fill up the markup with image sizes that aren’t needed?

Method 2 – Declare the sizes attribute for specific image sizes in specific templates

Another option is to add one or more functions in your functions.php to declare a custom sizes attribute for WordPress to use in place of the overly simplistic default. Here’s what that function looks like:

/* ADD CUSTOM RESPONSIVE IMAGE SIZES
================================================== */

function aw_custom_responsive_image_sizes($sizes, $size) {
  $width = $size[0];
  // blog posts
  if ( is_singular( 'post' ) ) {
    // half width images - medium size
    if ( $width === 600 ) {
      return '(min-width: 768px) 322px, (min-width: 576px) 255px, calc( (100vw - 30px) / 2)';
    }
    // full width images - large size
    if ( $width === 1024 ) {
      return '(min-width: 768px) 642px, (min-width: 576px) 510px, calc(100vw - 30px)';
    }
    // default to return if condition is not met
    return '(max-width: ' . $width . 'px) 100vw, ' . $width . 'px';
  }
  // default to return if condition is not met
  return '(max-width: ' . $width . 'px) 100vw, ' . $width . 'px';
}
add_filter('wp_calculate_image_sizes', 'aw_custom_responsive_image_sizes', 10 , 2);

This method is useful because you can declare the sizes attribute in one place and let WordPress do the work of applying it over and over. It’s also really useful because it’s the only way to override the overly simplistic WordPress sizes default for images added using the Add Media button in the Post / Pages editor.

In the function above, we’re telling WordPress how large images appear in blog posts – the full size we use for full width images and the medium size we use for half width images. A custom function is created with conditionals and that custom function is used to modify WordPress’s wp_calculate_image_sizes() function.

Using this method, you’d add images to your page template files using a variant on this simple function:

<?php the_post_thumbnail('large'); ?>
Method 3 – Declare the sizes attribute globally for specific image sizes

This methon is really useful for cases where you declare a custom image size and know that image size is always used in a single predictable layout at a single predictable display size. For example, perhaps you need a large image to show full width. You could set that image size using the add_image_size() as described above, then use the following in your functions.php to tell WordPress how large that image size appears everywhere:

function aw_custom_declare_custom_image_responsive_sizes($attr, $attachment, $size) {
  // Full width header images
  if ($size === 'xxxl') {
    $attr['sizes'] = '100vw';
  }
  return $attr;
}
add_filter('wp_get_attachment_image_attributes', 'aw_custom_declare_custom_image_responsive_sizes', 10 , 3);

This method adds a custom function to the the wp_get_attachment_image_attributes hook to tell WordPress that in every case everywhere that specifies the image size xxxl, the image should appear at 100% of the viewport width. You’d customize that as needed. You can add additional image sizes with additionalelse if conditionals. And as with Method 2 listed above, you’d then add the image into your template files using a variant on this simple function:

<?php the_post_thumbnail('xxxl'); ?>

Whew, that was a lot

Yeah, but it’s awesome because you can significantly reduce the amount of data needed to load pages on your websites while making images look sharp on all devices. Win / win. And WordPress is already set up for responsive images, so with a bit of customization, you can take full advantage of the technology.

Are you using responsive images in WordPress? Are you still awake after all that? Let us know in the comments.

Update

Updated the sizes examples above based on a few of the comments that came in – thanks + keep ’em coming.

blog post author avatar
Written with by Alex Wright

Runs a creative digital marketing, web design and SEO agency in Austin, Texas   |   Likes good looking, fast performing and high ranking websites   |   Doesn't want to understand Snapchat   |   Wants nothing to do with bananas   |   Wishes he were a BMX superstar

14 thoughts on “Responsive Images In WordPress

  1. Hi

    I stumbled upon this post while tearing my hair out over responsive images. I set up various custom sizes for the images on my site.

    So if you look at the first image on this page

    https://www.visitkievukraine.com/metrostations/lukianivska/

    You will see the code is:

    Then I went to Chrome developer tools and set the browser to Nexus 5 (360 x 640)

    My initial understanding of the srcset was that it would look at the viewport width (I thought it would be 360).

    I thought it would then choose to load one of the resized images (perhaps the 400 x 267).

    However I’m looking at the network tab and it looks like the original full-size image is being used.

    From the comment above I’m presuming the actual viewport width is not 360 and perhaps (360 x 3 – although I’ve no real idea to be honest).

    So my question is, and I don’t mean to be rude, is all this pointless? Or am I misinterpretting something/made an error?

    If I run this page through the Chrome developer (nexus 360 x 640) and look at the network tab, it looks like
    this image:

    https://alexwright.net/wp-content/uploads/2018/03/responsive-images-in-wordpress-composite-1024×449.jpg

    is the one that is actually being loaded, despite the srcset code

    1. Heya David! It looks like the main metro station image on your site is set up with responsive image sizes in the srcset but the sizes is set to the WordPress default which is the size of the image itself, in your case (max-width: 800px) 100vw, 800px and that’s not the correct size. That image (and maybe all your main images) would be sizes="(min-width: 1281px) 730px, (min-width: 960px) 590px, (min-width: 769px) 688px, (min-width: 481px) calc(90vw - 80px), calc(100vw - 40px)" or something close – I just gave it a quick once over. You need to figure out the size of the image display at each breakpoint.

      As to my blog page – it depends on your screen resolution in addition to the viewport width. You can head to this link to see your current device’s pixel density – https://bjango.com/articles/min-device-pixel-ratio/

      Hope that helps. Comment back with any other questions…

      1. Thanks so much. The penny hasn’t completely dropped yet. But I’ve just worked out where you got the sizes from. I’ll have another bash tomorrow, but it’s a lot clearer now.

        1. Yeah David, for sure keep in touch. Your css media queries use max-width rather than min-width so my sizes could use adjustment for that but hopefully you get the idea.

  2. Great and thorough writeup! I’ve been using these techniques for the last year or two on new sites. Figuring out the various needed sizes, with images going from 3 column, to 2 column, to full width as browser decreases, can be VERY complex and time-consuming. But when done, it is very elegant.

    But I’m wondering if there have been any advances or insight recently about the fact that all this work to ‘supposedly’ deliver smaller images to users on phones may be doing the opposite, due to pixel densities?!? So while I think my iPhone user is going to request my tiny 414px wide image, they may actually request the 1242px+ image because they have a newer phone with 3x pixel density. They may receive larger photos than my desktop viewers on their home fiber connections!

    Thoughts?!?

    1. This is a good point, Kenny. That 3x pixel density iPhone should get the 1242px+ image from your site. That iPhone is telling the browser – “my viewport width is an effective 414px wide (or whatever) and my pixel density is 3x, so give me what you got” and in many cases, for mobile devices with high pixel density, that will end up being a larger image than some desktop displays get.

      The idea behind responsive image technology is to give each device what it needs based on the viewport size and pixel density. The idea isn’t to restrict data based on presumed device type.

      In terms of advances / insight, to me the only solution that would work is a universally accepted, user driven browser setting that says “restrict my data, I’m on a slow or expensive connection” so that viewers could announce to websites that they are choosing to request smaller images and other restricted data based on their current connection.

      What do you think?

      1. I agree that the ‘proper’ image is probably being delivered to give the best ‘quality’ experience possible at various breakpoints. I just thought it’s interesting when reading about the reasoning & purpose behind coming up with responsive images in the first place, not serving huge images to people on small devices, which a lot of times also have more limited bandwidth, seems to be the main impetus. I agree it falls the browser to come up with a solution – bandwidth should be taken into equation when choosing proper images. But not sure this will happen. I just don’t think the average viewer is going to be able to tell much difference between that 414px wide vs 1242px wide average photo in most cases, unless they have young eagle-eyes and keep their phone a few inches from their face! So at least ONE of the main goals may have failed to a degree…

        1. Heya Kenny – I totally agree that mobile phones present a difficult dichotomy. On the one hand, they are often connected to expensive metered data connections. On the other hand, they have absurd pixel densities. When you double the pixel density, you quadruple the pixel dimensions of the image. You’re right that the original intention of responsive images may be subverted by ever increasing pixel densities.

          I can personally tell a great deal of difference looking at a lower resolution image on a high resolution display. To me, it’s unfortunate but I really notice the difference. But I don’t like wasting data. So I’m torn as well…

  3. As a web design newbie, I am constantly exploring online for articles that can help my new design business grow. I’ll be on the lookout for more responsive image tips. Thanks!

  4. Thanks for the tips – I had most of the pieces of th e responsive image puzzle but not all. Helped me get faster loading on mobile.

  5. Appreciating the time and effort you put into your blog and in depth information you offer.
    It’s nice to come across a blog every once in a while that isn’t the same unwanted rehashed information. Fantastic read!
    I’ve saved your site and I’m including your RSS feeds to
    my Google account.

Leave a Reply

Your email address will not be published. Required fields are marked *