So far we’ve been focused on how to make responsive images more performant. That’s essential, but at the end of the day, we still have the same old image on the page.
Now, it is time for the fun stuff!
Have you ever bemoaned the fact that your options for reliable image formats are limited to jpg, png, and gif? Ever wanted found yourself wondering if there is enough browser support for new formats like SVG or webp?
If so, you’re going to love the type attribute.
The type attribute can be added to <source> elements inside a <picture> element and allows you to declare different image types that the browser can choose from:
This new type attribute is modeled on the <video> element’s type attribute and works the same way.
The browser will pick the first source where the declared image type is one that it supports. If it doesn’t recognize any of the source types, it will use the <img> element’s src or srcset declarations.
The value is a MIME type for the image format being referenced in the srcset attribute. If you have multiple image URIs listed in the srcset attribute, they should all match the declared image MIME type.
Of course, you can combine type with the sizes and/or the media attributes as well. All three of these attributes are optional and can be combined to accomplish whatever you need.
When you’ve got a resolution switching use case, you want to empower the browser to make the best choice possible. This is what srcset is designed to do.
When you use the <picture> element with media attributes, you’re dictating to the browser what images it should use.
Therefore, you can and should use <picture> when you want both resolution switching and to support multiple image formats. Just leave off the media attribute so that the browser can do its thing.
Progressive enhancement for image formats
So far in this series, I’ve tried to keep things professional, but lighthearted. But that ends here because…
OMG! OMG! OMG! I’M SO BLOODY EXCITED ABOUT TYPES!
Phew, had to get that out of my system.
For years we’ve wanted to be able to use different image formats, but had to wait for wide spread adoption of the format.
But even when we finally felt we could switch, we always knew that we were ignoring old browsers. We’d chalk it up to progress and hope it didn’t affect too many people. Or maybe we never switched to the new image formats for fear of leaving people out.
But <picture> plus the type attribute gives use a way out of this conundrum. We can use progressive enhancement for image formats right now.
Sara Soueidan described how she is starting to do this for SVG with PNG fallbacks instead of all the hacks we used to use.
But it’s not just SVG and webp. What about JPEG-2000? JPEG-XR? APNG?
If you can find browsers that support an image format and you believe it can provide some value to your users, then there is no reason not to use that format so long as you provide alternatives.
JPEG-2000? Yes please!
A wonderfully in-depth article by Zoltan Hawryluk opened my eyes to the benefits of different image formats and in particular JPEG-2000 for alpha transparency images.
Look at those savings. The dice PNG at 1024×768 is 325.7K. The same image as JPEG-2000 is only 19.2K. That’s insane!
I know what you’re thinking. That’s wonderful, but no browsers support JPEG-2000.
That’s what I thought too, but I was wrong. Both desktop and Mobile Safari already support JPEG-2000.
Now before you go converting all of your images to JPEG-2000, heed Zoltan’s warning:
As you can see, the numbers for JPEG-2000 are especially impressive. However, the file sizes of the alternate images will vary depending on the characteristics of the original image… While alternative image formats may give better results, sometimes they don’t.
So it will depend on the image and the design. But you can see how there can be significant benefits for some of your users depending on the types of images and the formats their browsers support.
Brave new world of image formats
I don’t expect anyone to go off and immediately start using JPEG-2000. There’s a lot more work to be done in this space so that we know what image formats make sense and when to use them.
Other than the command-line tools, I find the tools to be awkward and rough around the edges. There has been no incentive for companies like Adobe to add rich support for image formats like JPEG-2000 because no one could use them until now.
We have a lot of experimenting to do. I can’t wait!
What about CSS?
Everything we’ve talked about so far has been for inline responsive images. Because we already had media queries in CSS, inline responsive images were the biggest challenge and most of the focus has been on them.
But there are some new standards for responsive images in CSS and a few tricks you should know. Stay tuned for Part 8: CSS Responsive Images.
Each source has a required srcset attribute along with optional attributes including media, sizes and type. Both sizes and srcset on a <source> element work exactly the same as they do on an <img> element.
We're going to focus on the media attribute for now.
The value of the media attribute is a media query. Unlike the media condition that the sizes attribute uses, this is the full media query that you've come to know and love.
As the browser looks through the list of source elements, the first source whose media query matches is the one that is used. If no media queries match, then the <img> element is used.
Media attribute is a directive, not a suggestion
Unlike srcset and sizes, when you use the media attribute, you are dictating to the browser which source should be used.
The browser has no discretion to pick a different source. It must use the first <source> element whose media attribute matches the current browser conditions.
This is why the <picture> element with the media attribute is perfect for art direction. In the art direction use case, designers need to ensure that the image used at a particular viewport size is exactly the one they intend otherwise their design may break.
Let's take a look at this in action.
Picture element in the wild
Shopify uses the <picture> element for art direction. Shopify's home page highlights one of their customers, Corrine Anestopoulos, the Founder of Biko Jewellery.
On narrow screens, the photo of Ms. Anestopoulos is cropped. Because the image is no longer simply being scaled down, this is considered art direction.
The markup that Shopify uses combines the <picture> element with srcset display density descriptors. I've simplified the markup to remove long image paths and included it below:
Looking at the code in more detail, what we see is the Shopify has three different image breakpoints. The image is a fixed width at each breakpoint—it jumps from size to size instead of flexing between breakpoints.
Because the image is fixed width, srcset display density descriptors make sense. So for each breakpoint, Shopify has defined a 1x and 2x source file. It breaks down like this:
<source … media="(min-width: 990px)"> — The largest image size, which Shopify calls desktop, is the first source. The media attribute tells the browser that this source should only be used if the viewport is larger than or equal to 990 pixels wide.
<source … media="(min-width: 750px)"> — The second source, the "tablet" image, will be used for viewports larger than or equal to 750 pixels. Because the first source takes effect at 990 pixels and the browser selects the first source that matches, the effective range of the second source is from 750 to 989 pixels.
<img> — If there are no matches for the two sources, then the viewport must be smaller than 750 pixels wide. When that is the case, the srcset on the <img> element will be used. This "mobile" image is the cropped image used for small screens.
Sadly, that solution rarely makes it into production on the projects I’ve worked on. Sometimes browser support is the culprit. Other times we’ve inherited particularly uncooperative grid patterns (either from an existing project, or an overzealous framework).
So I’ve written a jQuery plugin for equalizing element heights. It’s called Leveller:
When we last left our intrepid web developers, they had discovered the power of srcset width descriptors, only to be faced with a new challenge—the browser only knows the size of the viewport when it begins downloading images.
Now, it is time to meet the hero of our story: the sizes attribute.
Sizes attribute is required!
The sizes attribute is required any time you use srcset width descriptors.
In fact, sizes only makes sense if you’re using the width descriptors. If you’re using the display density descriptors, you don’t need the sizes attribute. The browser won’t know what to do with it.
Out of all the new responsive images standards, sizes was the hardest one for me to wrap my head around at first.
Like srcset, the sizes attribute contains a comma-separated list. This comma-separated list describes the size of the image in relation to the viewport.
I want to repeat that point because it is the key to understanding sizes.
We’re telling the browser what size the image will be in relation to the size of the viewport. And we can tell the browser how that relationship changes as the size of the viewport changes.
Like srcset, each comma-separated item contains two values separated by a space.
The first value is a media condition. A media condition is similar to a media query, but not as full featured. For example, you can’t do things like ‘@media screen’, but you can do everything else you would likely want to do in sizes.
Most commonly, your media condition is going to be a something like ‘(max-width: 480px)’ or maybe ‘(min-width: 480px)’.
The second value in each comma-separated item is a length. This length is often expressed using the viewport width (vw) unit.
Each vw unit represents 1% of the viewport width, which is a fancy way of saying that 100vw is 100% of the viewport width and 33vw is 33% of the viewport width.
The length doesn’t have to be expressed as a viewport width unit. It can be any length including absolute and relative length. You can even use CSS calc() to do things like auto-calculate margins dynamically.
How does the browser select the correct sizes value?
When the browser starts through the comma-separated list of values, it grabs the first value where the media condition passes.
Take another look at our sample markup and the order in the sizes attribute:
If we translated this into a bulleted list of instructions, it might look like this:
(max-width: 480px) 100vw — If the viewport is 480 pixels wide or smaller, the image will be 100% of the viewport width.
(max-width: 900px) 33vw — If the viewport is 480 pixels wide or smaller, this rule will never be reached because of the previous media condition. Ergo, if this rule effectively says that if the viewport is 481 pixels wide to 900px, that the image will be 33% of the viewport width.
254px — When there is no media condition listed, the length is assumed to be a default value used when none of the other media conditions are met. In this case, we have media conditions covering viewports up to 900 pixels. Therefore, from 901 pixels wide to infinity, the image will be 254 pixels wide.
To help you visualize how this might work in the real world, I created a little video that looks as how the values might change as the viewport width increased on the Walmart Grocery site.
NOTE: As of the time of publication, the Walmart Grocery site was not using srcset and sizes. This is hypothetical markup. If you want to see srcset and sizes in action, take a look at The Guardian which recently switched to using srcset and sizes.
But what about separation of content and presentation?
I’ve seen many complaints about the new responsive images specification. Most amount to either complaints about complexity that ignore the fact that images on the web are inherently complex3 or some variation of WWIC.
But the one complaint I have a tremendous amount of sympathy for is the idea that we now have presentation information—the size of the image—in the markup. I doubt there was anyone involved in the responsive images standards process who didn’t share this concern at some point.
Unfortunately, it is unavoidable. As discussed in Part 4, the browser starts downloading image sources before the size of the image in the page is known.
The only way to support the pre-loader and make sure the right source gets downloaded is to provide some information about the size of the image in the markup.
Is the pre-loader worth it?
If you’re like me, you may have found yourself wondering whether the pre-loader was worth all of the problems it causes?
Yes. Yes, it is.
Andy Davies wrote about how Google saw a 20% and Firefox a 19% increase in average page speed after implementing the pre-loader. Steve Souders thinks that “preloading is the single biggest performance improvement browsers have ever made.”
We can’t simply throw out that web performance boon in favor of responsive images.
Therefore, we have to find a compromise. The sizes attribute is that compromise. It provides just enough information for the browser to do its job.
Srcset and sizes = Smart browsers
Srcset and sizes provide all of the functionality you need for the resolution switching use case. They give the browser just enough information to allow it to make smart decisions.
But what happens when you need more control? What about art direction?
Next Tuesday, Responsive Images 101, Part 6: The Picture Element.
The width of the image source can cause some confusion. Width descriptors are looking for the resolution of the source file.
In other words, if you open the image in an image editor, what does it say the resolution is? Grab the width and put it in the srcset attribute.
The browser picks the best source?
When you use width descriptors, you’re providing the browser with a list of images and their true widths so that it can select the best source. How does the browser do that?
Your first instinct is probably to say that the browser looks at the size of the element in the page and compares it to the list of source sizes. That makes sense, but it isn’t how the selection work.
See, when a browser starts downloading images, it often doesn’t know the size of the image in the page.
Browser pre-loader and speculative asset downloading
If you look at a timeline of how a browser renders a page, you’ll notice something striking.
The only thing that the browser does know is the size of the viewport. Once we move past display density descriptors, everything hinges on the size of the viewport.
Why does this matter?
The viewport can be a poor substitute for the actual size of the image. Take the images on Walmart’s Grocery site:
On narrow viewports, the images are nearly the same size as the viewport width. They are certainly close enough to work.
Wider screens, however, are a different matter:
In the second example, the viewport is 1540px wide, but the images are only 254px wide. Knowing the size of the viewport won’t tell the browser enough information to be able to select the right image source.
Sizes to the rescue!
How do we tell the browser about the size of the image in the page so that it can download the right source from our srcset list? Use use the sizes attribute!