live demo - use your dev tools and turn off caching and watch the different image assets load as the viewport is resized.
In the world of responsive design, the ultimate goal in handling images is to load different versions of an image based on need. Don't stretch small images on big displays. Don't load massive images on tiny displays, slowing web sites down and wasting data.
The problem: Many variables can affect the appropriate size image to load. The information that the browser knows is complimentary, but mutually exclusive from the information that the server knows at the time it is needed.
|Variable||Browser / User's Device Knows||Server / Designer Knows|
|Size of screen||Yes||No|
|Pixel density of display||Yes||No|
|Quality and speed of network connection||Yes||No|
|User preferences (e.g. accessibility settings)||Yes||No|
|Size of the image in pixels||No||Yes|
|Size the image will occupy in viewport||No||Yes|
The solution: Tell the browser the information it doesn't already know and let it decide which image asset to use.
This does not mean telling the browser which image to use! It means giving the browser the information it doesn't already know, offering size options, and letting it make an informed decision about which one to download.
Tell the browser:
- Image dimension in pixels
- Final size the image will be displayed on the page
Having all the variables, the browser will then determine which image to load based on all conditions - display size, density, even network speed.
SVG formatted vector images do not need alternate versions or any special code, because they already scale infinitely without losing sharpness or quality.
There are two general use cases for responsive images - resolution switching, and art direction.
This is the most common use case, which is that you want to load different sizes of the same picture. Here's an example:
<img src="cat.jpg" alt="cat" srcset="cat-160.jpg 160w, cat-320.jpg 320w, cat-640.jpg 640w, cat-1280.jpg 1280w" sizes="(max-width: 480px) 100vw, (max-width: 900px) 33vw, 254px">
imgtag is always needed
srcis always needed and should provide a default/fallback image, particularly for old browsers that don't support
w(width) descriptors of the actual pixel width of the image.
sizesis required any time you're using
sizesis a list of conditions (similar to media queries) along with the size the image will be displayed in your layout. You can use any type of units here (
px, viewport units, etc. You can even use the
- Always provide the
sizesattribute with a default size (in this case 254px).
Art direction is when you want to load a different picture content based on certain conditions. For example, a horizontal image on large displays may become a cropped, portrait version of the image on mobile.
<picture>is designed for art direction as opposed to simple resolution switching. It's also for image type switching, which is an excellent, forward looking feature.
<picture> <source media="(min-width: 900px)" srcset="cat-horizontal.jpg"> <source media="(min-width: 650px)" srcset="cat-vertical.jpg"> <img src="cat.jpg" alt="cat"> </picture>
<source>can have a full set of srcsets and sizes just like those used for resolution switching.
imgtag is still always required.
- This can also be used to offer multiple formats of the same picture, so browsers that support newer image formats like webp can take advantage of better image compression.
New Picture Formats
These new image formats improve on the compression algorithms of traditional jpegs, improving file sizes without reducing quality. None of them are cross-browser supported yet though, so for now they should only be used with the
<picture> tag defined as additional sources.
||Chrome, Firefox, Edge, Opera, Android browsers|
||IE and Edge|
||Safari (macOS and iOS)|
|APNG (Animated PNG)||
||Chrome, Firefox, Safari (macOS and iOS), Opera|
Moving Into CSS
Not well supported yet. Use media queries to swap out background images if performance is an issue.
(Lack of) Separation of Content and Styles
Why can't this be done in CSS? What happened to separation of content and styling?!
When loading a web page, the browser aggressively opens multiple connections to download all the assets it finds in the HTML as soon as it sees them. This begins happening before the CSS is being parsed.
This feature in browsers is called "pre-loading" or "speculative asset downloading" depending on which browser vendor you talk to. Both Firefox (Gecko) and Chrome (Blink) conducted performance tests, and both found that web pages load 20% faster using this feature alone. So that's not going to change any time soon.
This creates a problem for developers - we can't tell the browser information about images using CSS, because that's after the browser has already opened connections and started downloading images!
Fixing this, for now, requires putting these style related settings in the HTML markup. It's not a perfect solution, but it works.
How to Set Image Breakpoints (How many images do we offer?)
No real clear answer, but Jason Grigsby does a good job addressing the approach.
Using some math to calculate how many "wasted bytes" are loaded for images at different sizes, there is more waste as the image gets larger.
Loading anything larger than the way it will be displayed is technically wasting bytes. So in theory, you shouldn't space the image breakpoints evenly, you should provide more sources toward the larger end of the spectrum.
Images that benefit the most from having additional options are those with a lot of texture and color, because the jpeg compression is less efficient. Images that compress well anyway technically don't need as many sources. This however is getting pretty far into the weeds looking at each image asset individually. Very tedious.
You can also optimize the source options based on which size image is downloaded most often.
The bottom line here is again that there's no silver bullet answer, and that really this process should be automated or done by a computer. In the future, it probably will be.