Skip to content

Beginner’s Guide to Responsive Images: How to Get Them Right

If you’re relatively new to responsive design or if you simply want a quick reference for the different things you can do in HTML and CSS to incorporate responsive images in your projects, this responsive images tutorial should help.

At this stage, making websites look good and perform well on multiple devices and platforms is part and parcel of good web design and development. There’s no more separation between “mobile design” and “desktop design;” every website built today should be responsive and should work reasonably well on every device. A big part of the responsive design process is responsive images.

Responsive images

This responsive images tutorial will go through CSS techniques, HTML features, and some tools you’ll want to consider. All of this should give you a good overview of getting started with responsive images in your projects today.

📚 Table of contents:

Responsive images with plain CSS

The simplest way to make any image on a web page responsive doesn’t require media queries or extra HTML. You can make any image grow and shrink depending on the size of the window with a couple of lines of HTML and CSS.

First, my HTML will include width and height attributes:

<img src="images/leopard.png" alt="Responsive images: Leopard on a tree branch" width="1000" height="667">
Code language: HTML, XML (xml)

Including the width and height values in the HTML is best practice. This ensures that the browser reserves the necessary space for the image and there’s no subsequent page reflow as the image is loading.

Along with that, I’m going to use the following CSS:

img {
  max-width: 100%;
  height: auto;
Code language: CSS (css)

These values will override my HTML. The max-width property is set to 100% to ensure it fills whatever space is needed, up to a maximum of 1000px (the value from the HTML). The height value of auto ensures that the height of the image keeps the image dimensions proportional with its natural width and height. If I remove the height: auto line, the image will stay at the height defined in the HTML, regardless of the width – which is usually not what I want.

You can try out this simple example using the following CodePen. It’s best to open the demo in a new window if you want to test out the responsiveness.

And note that in my example, the image’s natural dimensions are 2000px x 1333px but I’m choosing to display it at a maximum of 1000px.

Theoretically, I could do the above for every image on my page, and this would be a rudimentary and acceptable way to incorporate responsive images into my projects. But ideally, I’d like to take this to the next level and gain control over the image’s resolution and other factors, to improve performance and help with SEO, which I’ll discuss in the following sections.

Responsive images with the srcset and sizes attributes

In the simple CSS example above, I’m loading an image that’s about 1.44MB in size – even after I’ve used lossless compression to reduce the size. That’s not terrible on its own when viewed on a desktop, but it’s certainly not the size I want loaded on a small device, like a smartphone. This is where the srcset and sizes attributes come in handy.

The srcset attribute allows you to specify multiple image sizes in a single value. These will be the images that the browser or device will have access to under defined circumstances. The sizes attribute works along with srcset to tell the browser which of the images to choose.

Here’s an example that uses multiple versions of the leopard.png image from the previous example:

<img srcset="images/leopard-480.png 480w,
             images/leopard-800.png 800w,
             images/leopard.png 2000w"
     sizes="(max-width: 600px) 480px,
            (max-width: 1000px) 800px,
     alt="Leopard on a tree branch">
Code language: HTML, XML (xml)

If you’ve never seen the srcset and sizes attributes before, that might seem confusing at first glance. I’ll break it all down so it’s relatively easy to grasp.

Breaking down the srcset attribute

The srcset attribute accepts a comma-separated list of one or more strings. Each string contains:

  • A URL pointing to an image
  • One of the following optional descriptors (separated by a space):
    • A width descriptor
    • A pixel density descriptor

In my example, I’ve included a width descriptor, which is the one you’ll see most often. I’ve included three different versions of the image: The large high-resolution version, along with one that’s 800px wide and another that’s 480px wide.

Notice when I used the width descriptor in the above example, the syntax is the width value immediately followed by a “w” (don’t use a “px” unit value!). For each of the width descriptors representing the images, I’m using the intrinsic width of the image in pixels. You can get the true size of any image in any of several different ways – by referencing its properties in your file system, a photo editor, or even in your browser or browser’s developer tools.

Breaking down the sizes attribute

The sizes attribute only works along with the srcset attribute. You can use srcset alone (see the next section), but the most common way to use srcset is along with sizes.

The sizes attribute accepts a comma-separated list of one or more strings. Each string contains:

  • A media condition (similar to media queries used in CSS)
  • A value defining the size of the “slot” the image will take up

The slot value can be an absolute length like em or px or a viewport relative unit (e.g. vw). Notice in my example the slot values in the sizes attribute don’t exactly match the three width descriptors. Here is the code again:

<img srcset="images/leopard-480.png 480w,
             images/leopard-800.png 800w,
             images/leopard.png 2000w"
     sizes="(max-width: 600px) 480px,
            (max-width: 1000px) 800px,
     alt="Leopard on a tree branch">
Code language: HTML, XML (xml)

The fact that the slot values don’t match exactly to the width descriptors is fine. In my case, I can break down the sizes value as:

  • A 600px wide viewport will load the 480w image from the srcset value inside a slot that’s 480px in width.
  • A 1000px wide viewport will load the 800w image in an 800px slot.
  • The default full size image (2000w) will fill a 1000px slot if the previous media conditions aren’t met.

The last string is a slot value alone, with no media condition. As mentioned, this ensures the browser will have something to display if none of the media conditions are met, working as a default.

You can view the example code in action using the CodePen demo below. Note that in this case, you’ll have to test on something that mimics different devices (like the DevTools in Chrome). You can also open the page using a variety of real devices to do a true test. For convenience, I’ve included a text overlay on each of the images so you can see which loads when you view the page.

Notice that after the original image loads, the image doesn’t change size when you change the size of the viewport. The srcset and sizes attributes are useful for loading images according to media conditions on first load, but won’t help to switch images based on screen resizing. Later I’ll show you a different responsive images feature that will solve that problem.

Using srcset with a pixel density descriptor

Earlier, I’ve mentioned that the srcset attribute can be used with a pixel density descriptor. This descriptor lets the browser decide which image to use based on the device’s resolution capabilities. Here’s what that looks like:

<img srcset="images/leopard-480.png,
             images/leopard-800.png 1.5x,
             images/leopard.png 2x"
     alt="Leopard on a tree branch">
Code language: HTML, XML (xml)

Notice a couple of things here. Firstly, for the regular src attribute, I’m using the smallest image, ensuring a mobile-first approach. Next, the srcset attribute includes a few other versions of the image, with resolution indicated by the 1.5x and 2x descriptors. The 480 image doesn’t include a descriptor because the 1x is implied. Finally, notice there’s no sizes attribute present, which I don’t need in this case. MDN explains how the browser chooses the image:

The user agent selects any of the available sources at its discretion. This provides them with significant leeway to tailor their selection based on things like user preferences or bandwidth conditions.

To understand how the descriptors work, just remember that one device pixel represents each CSS pixel. So 1x would be a 1:1 ratio, 1.5x would be a 1.5:1 ratio, and so on. You can try it out in the CodePen below, but you’ll have to use different devices (or use a tool that mimics them) to see the difference.

Using the <picture> element

So far, the features I’ve discussed for incorporating responsive images are assuming that I’m always displaying the same image but at different sizes and resolutions. And although I’m using CSS in all the examples to change the width of the images when the user resizes the browser, the image itself never actually changes once the page is loaded.

The <picture> element is an HTML feature that allows you to offer alternative versions of an image based on the presence of specific media features. This also allows images to be switched out when the user resizes the viewport and essentially allows you to do art direction with your images, showing varieties of the same scene but cropped or zoomed differently depending on the device size.

For example, a wide shot with a small object in the middle would be appropriate for a larger device on a desktop or tablet, but a smaller device like a smart phone could load the same image cropped or zoomed-in.

Here’s some example code that will allow me to do some art direction on my image:

  <source media="(min-width: 1000px)" srcset="images/chipmunk.png">
  <source media="(min-width: 800px)" srcset="images/chipmunk-zoom.png">
  <img src="images/chipmunk-closeup.png" alt="Chipmunk in a field on a rock">
Code language: HTML, XML (xml)

Notice the following about the code:

  • The <picture> element accepts multiple nested <picture> elements as children
  • Each of the <source> elements inside <picture> is using the media attribute to define the media condition that triggers use of that source image
  • The <picture> element accepts the regular &lt;img&gt; element as a child, which the browser recognizes as a fallback if it doesn’t support <picture>
  • There are no attributes directly on the <picture> element (<picture> only accepts HTML’s global attributes and doesn’t have any attributes of its own)

The CodePen below demonstrates this:

If you open the demo in a new window, you can resize the window to see the image change. Notice how the subject of the image gets more zoomed-in as the browser window gets smaller. This is an easy way to do responsive art-directed images that look appropriate on whatever device is being used. Of course, this takes a little more work, but it’s worthwhile if you want your images to be meaningful on any device used.

Tools and services to help with responsive images

There are countless tools available, both free and commercial, that will assist with implementing responsive images. And some of these will help you avoid even having to write much of the code I’ve discussed. Here are a few that you might find useful:

  • Responsive Image Breakpoints Generator – Online tool to easily generate optimal responsive image dimensions.
  • Images Responsiver – A Node module that transforms simple HTML image syntax into better responsive images syntax.
  • gatsby-plugin-image – A Gatsby pluign that handles the hard parts of producing images in multiple sizes and formats.
  • lazySizes – A fast, jank-free, SEO-friendly, and self-initializing lazy-loader for images (including responsive images picture/srcset), iframes, and more.
  • WURFL.js – JavaScript that detects device models of smartphones, tablets, smart TVs and game consoles accessing your website.
  • Picturefill – An old project that allows you to use the <picture> element on older browsers. I’d recommend avoiding this tool as it will likely bloat your code on browsers that are already slow to begin with. Appropriate fallback techniques or a mobile-first approach are probably better.

Importantly, and conveniently, a number of different services can do responsive images automatically, offering features like different image sizes, an API for on-the-fly image generation, and more.

Even WordPress itself comes with built-in support for responsive images (starting in version 4.4).

Another tool/service worth looking into is Optimole. It’s an advanced image optimization and delivery tool built by the team behind Themeisle. This one will not only reduce the disk size of your images without the visual quality suffering but will also take care of delivering the images to your website visitors through an image CDN. One of the aspects of this image delivery feature is that your images will also be optimized for viewing on different devices.

There’s a free version of Optimole available. It allows for up to 5,000 website visits monthly and will give you all the auto-scaling features, CDN, and more.

What is your experience with responsive images on websites? Let us know in the comments below.

Don’t forget to join our crash course on speeding up your WordPress site. Learn more below:


Layout and presentation by Chris Fitzgerald and Karol K.

Yay! 🎉 You made it to the end of the article!
Louis Lazaris

Inline Feedbacks
View all comments

Or start the conversation in our Facebook group for WordPress professionals. Find answers, share tips, and get help from other WordPress experts. Join now (it’s free)!

Would love your thoughts, please comment.x