The Quick guide to responsive images

Images tell stories. Images give you online identity. You’ll agree with me when I say they’re one of the most important pieces of each and every website. Nevertheless they’re also the number one problem when creating a fully responsive browsing experience. Most of us want our website images to look sharp and crisp across all devices. The easiest way to achieve this is to serve high resolution images. The issue with this approach is that high resolution images tend to have large source files. Although most of these are put to good use on large screens, to the contrary on small or low resolution screens responsive images are complete waste and can drastically affect the website performance.

Fortunately for us there a few new pieces of markup that can help us solve our responsive images problem.

I call them “new pieces” in this post because they aren’t yet supported by all browsers. They’re also still under active development. This shouldn’t prevent you from learning more about them or even using responsive images on your website since there’s a Polyfill for browsers that lack support.

Lets take a look and dive a little deeper into responsive images.


The easiest way to get our images to scale across varying viewport widths and screen resolutions is by offering the browser multiple resolutions of the image using srcset.

In the code snippet above you can see the srcset attribute in action. It contains a comma-separated list of resource URLs. After each URL the image pixel width is specified (using w descriptor). The browser uses these “specified widths” to do some calculations and pick a source to load from the set we specified.

Note that the image still has a src attribute, which will load in browsers that don’t support the new (srcset) syntax.

It’s also worth noting that the spec allows us to supply ratios directly. Also that sources without a descriptor get assigned a default ratio of 1x, allowing us to write something like this:

This is a nice and simple way to adapt the image to varying device-pixel-ratios but keep in mind that this doesn’t work for fluid images (fixed-width only). For fluid images the best solution is to use a combination of srcset and sizes attributes.


To help the browser pick between the images we provided in our srcset attribute, we need to give an estimate of the image’s display width. In other words, how much real estate it will occupy by using the sizes attribute.

In the snippet above, the image occupies the full width of the viewport (100vw).
This is the simplest use case but sizes attribute can get fairly more complex. It allows us to supply it with multiple lengths (in a comma-separated list) and attach media conditions. Take a look at the following code snippet.

The sizes attribute suggests that our page layout has a breakpoint at 40 ems. This means that the layout of our page changes when the viewport reaches the said breakpoint. Below that breakpoint, the image will fill 100% of the viewport’s width (100vw). Above the breakpoint the image will take up the 3rd of the viewport width (30,3vw).

For example, imagine that you have a gallery with three images in each row. Below the 40em breakpoint the images in the gallery take up the full width of the page and stack one on a top of the other.

The important thing to note is that CSS lengths for sizes attribute can be either absolute (ex. 100px or 20em) or relative to the viewport (33.3vw, as in our snippet). That “relative to the viewport” part is what enables images to flex.

With sizes length and a set of sources in srcset to choose from, the browser has everything it needs to efficiently load an image in a fluid layout. It also has enough information to adapt the image to varying device-pixel-ratios by using some math we won’t cover in this post.


For images that simply need to scale, we list our sources and their pixel widths in srcset and let the browser know how wide the img will display with sizes. There’ll be times when we want to adapt our images in ways that go beyond scaling. This is where the picture element comes in.

For example we may have images with a 16:9 ratio on our page. They look great on the large screen but on smaller screens they look tiny. Using the picture we can add the new cropped, square images for our small screens in the source.

If we were to include our cropped images in a srcset, there’s no telling when they’d get picked since the browser is making the calculated choice. Using picture and source media, we can explicitly tell the browser to only load the wide, rectangular crops when the viewport is wider than 40em and always load the squares on smaller viewports.

A picture element contains any number of source elements and one img. The browser goes over the picture’s sources until it finds one whose media attribute matches the current environment. It sends that matching source’s srcset to the img, which is still the element that we “see” on the page.

Simpler use case:

On landscape-oriented viewports, landscape.jpg is fed to the img. When we’re in portrait (or if the browser doesn’t support picture) the img is left untouched, and portrait.jpg loads.

Unlike audio and video elements, picture is an invisible wrapper which simply feeds its img a srcset. This means that all styling needs to be applied to the img and not on the picture.
picture {width: 100%} does nothing.
picture > img {width: 100%} does what you want.

picture also makes offering multiple formats easy by following the same source type pattern established by audio and video:

If the browser supports a source’s type, it will send that source’s srcset to the img.

In this example if the browser doesn’t understand the image/svg media type, it will skip it. The same goes for image/png type. If the browser doesn’t support any of the source types it will fall back to src attribute in the img element (in this case logo.gif).

Responsive Images – The Conclusion

We’ve been serving huge images for huge screens across every device for years now. These new markup elements provide us with the tools to fix that problem. They allow us to send different sources to different clients. We’re finally able to send each of our users the source tailored for their specific device. By using these new markup elements we’re able to achieve huge improvements in page performance and speed.

As I’ve already mentioned, the specification is not yet final. Only a few browsers support responsive images features ( However, I still encourage you to learn this new markup and experiment with it.

If you want to use it in production there’s a great Polyfill for browsers that don’t support the markup for responsive images.

About Luka Čavka

I’m a front-end developer from Split, Croatia, with a passion for responsive web development, especially HTML and CSS coding. During 7+ years of professional experience I have worked with clients from various fields and have published more than a few hundred websites. In my spare time I enjoy tinkering with new front end tools/techniques and having a beer (or two) at the local pub.