Skip to content
Business Success
Core Web Vitals
Optimization Techniques
Metrics & Charts

Best Practices for Optimizing Images

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

Serve the right image size

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:

  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:

  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.

Use the right format

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:

  • JPEG: JPEG’s are the most common image format found on the web and work well for photographic images, though there are newer formats like WebP and AVIF that have better compression, leading to much smaller image sizes.
  • PNG: The PNG format is a much higher fidelity image than the JPEG format, and can support transparency. But that improved fidelity comes at the cost of large file sizes so you’ll want to make sure that you compress any PNG’s you’re using with a tool like ImageOptim or Squoosh. You should also avoid using the PNG format for detailed, photographic images.
  • WebP: The WebP format has much better built in compression than the PNG and JPEG format and is now broadly supported. It’s probably a better choice than PNG and JPEG in most situations.
  • AVIF: The AVIF format is another newer format that boasts much better compression rates than JPEG and PNG, and typically even better compression than the WebP format. Because it’s newer, you should make sure to provide fallback formats for legacy browsers that do not yet support the format.
  • SVG: The SVG format is a vector format (meaning, it stores instructions about how to recreate the image, rather than image data itself) so it compresses extremely well. It works best for simple images, however, as the more detailed the image, the more instructions must be provided for it to be displayed. This format works great for icons and logos, and scales automatically on different resolution displays.

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.

Apply lazy loading to non-critical images

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.

Make sure images have dimension attributes

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.

Read Next

Best Practices for Optimizing JavaScript

This guide walks you through essential techniques for reducing the negative impact of JavaScript on your pages by focusing on reducing the impact on the initial load, as well as reducing the impact of the actual JS interaction itself.

Leveraging the Browser Cache for Faster Load Times

In the world of front-end performance, reducing the number of HTTP requests is still the best way to speed up your site. First step: leverage the browser cache.