They say a picture is worth a thousand words. Unfortunately that picture can also cost you 1,000 kilobytes. Images are an important part of providing a rich, user-friendly experience online. It’s critical to optimize how they’re loaded and how much they weigh – making sure your beautiful images aren't hurting your page speed.
Image: Freepik
If you do one thing and one thing only to optimize your images, it should be to make sure that your images are properly sized so that you’re not serving any images that are larger than necessary. The web is littered with images that are much larger than they need to be.
An image that will be displayed at 100px by 100 pixels should ideally be 200px wide and 200px tall if you’re targeting any higher resolution screens, and as close to 100px by 100px if you happen to be targeting any lower-end devices that still have a lower resolution display.
You can ensure that the correct size image is displayed by using some combination of the srcset
and sizes
attributes.
The srcset
attribute lets you provide a list of image sources to the browser. The browser will then choose the most appropriate image to serve based on the size of the image and the resolution of the screen.
For example, using our example above, if we have an image that will display at 100px by 100px, we may create two versions of that image—one that is 100px by 100px and one that is 200px by 200px. We could then provide each image source to the browser like so:
<img
width="100"
height="100"
src="our-image-100.jpg"
srcset="our-image-100.jpg 1x, our-image-200.jpg 2x"
/>
This snippet tells the browser that this image has two possible sources and that for a low resolution display (1x
) it should use the 100px image while for a higher-resolution display (2x
) it should use the 200px image.
The previous example using srcset
is perfect if our image is always displayed at 100px by 100px. Frequently, we may want to change the way an image is displayed though (example: it may be a larger hero image on large displays, but a much smaller article header on small screens).
In cases like this, srcset
alone won’t quite do it. Instead, we have to use the sizes
attribute to tell the browser the size the image will be displayed at.
For example, we might extend our previous snippet a little bit:
<img
width="100"
height="100"
src="our-image-100.jpg"
srcset="our-image-100.jpg 1x, our-image-200.jpg 2x"
sizes="(min-width: 60em) 100vw, 100px"
/>
Now we’ve told the browser that if the screen is at least 60em wide, the image will be displayed at 100 viewport widths (100%). On smaller screens, it will be displayed at 100px.
Now the browser has all the information necessary to choose the correctly sized image depending on the size and resolution of the display.
There are quite a few different file formats out there for images, and they each have different ways of storing information about what the image is comprised of, as well as different ways of compression that information. After using appropriately sized images, choosing the right format is the next most important decision you can make.
While new image formats are constantly being experimented with, here are the primary formats you should be aware of:
Whatever format you use, you’ll want to make sure the images are compressed well. You can do this manually with a tool like Squoosh, but for larger sites and easier longer-term maintenance, you’ll want to use a CDN or dedicated image service that can handle the proper sizing, compression and file formats for you.
There can be a lot of images on a single page, but not all of those images are equally important. Lower priority images (images that are initially hidden, or outside of the initial viewport display) aren’t as important to request early and should be lazily loaded (loaded after the initial loading of the page, only when they’re needed). Making sure those images are only loaded when needed frees up the network for more critical resources.
We can help the browser make smarter decisions about how eagerly to load images by using the loading
attribute on our img
elements.
The loading
attribute tells the browser how aggressively to load a particular image, and is supported by all major browsers.
There are two possible values for the loading
attribute:
eager
This tells the browser to load the image immediately (this is the default value of the attribute)lazy
This tells the browser to wait to load the image until it is nearly within view (the exact distance varies by browser, and in some cases, by network connection).For a hero image, we may choose to use the eager
value to tell the browser that this image is important to load right away:
<img loading="eager" src="my-hero.png" />
For images further down the page, we would want to tell the browser to wait to load those images until they’re needed:
<img loading="lazy" src="later-image.jpg" />
Note: Lazy-loading images used to require JavaScript and you’ll still see many sites and examples that use JavaScript for that purpose. Now that we have a native browser-supported way to lazy-load images, however, using JavaScript to lazy-load them is usually unnecessary and in most cases is an anti-pattern.
When an image is going to be displayed on the screen, the browser must figure out how much room the image will take up so that it can rearrange the rest of the content on the page.
Until the image is downloaded and the styles have been calculated, the only way the browser can tell how much space to preserve is to look at the height
and width
attributes on the image. If those attributes are missing, the browser won’t preserve any space for the image initially. Then, when the image arrives, the browser will have to rearrange the content to make room for the images, leading to a layout shift.
Wherever possible, make sure to include height
and width
attributes on your images to avoid layout shifting.
<img src="my-image.png" height="100" width="100" />
The height
and width
attributes do not have to be the exact size of the image, or even the exact size the image will be displayed at. As long as the dimensions are proportionate the browser will be able to preserve the correct amount of space.
For example, an image that will eventually be displayed at 1000px by 500px can safely be given height
and width
attributes of 500px and 250px.