---
title: Serve correctly sized images with srcset and sizes
description: >-
  Use `srcset` and `sizes` attributes with Shopify's `image_tag` filter to serve
  the smallest image that still looks good at each viewport size.
source_url:
  html: >-
    https://shopify.dev/docs/storefronts/themes/best-practices/performance/use-responsive-images
  md: >-
    https://shopify.dev/docs/storefronts/themes/best-practices/performance/use-responsive-images.md
api_name: liquid
---

# Serve correctly sized images with srcset and sizes

Use `srcset` and `sizes` attributes with Shopify's `image_tag` Liquid filter to serve appropriately sized images for each viewport.

***

## Why

Without `srcset` and `sizes`, the browser has only one image to download regardless of the viewport. Mobile devices download desktop-sized images unnecessarily, wasting bandwidth and slowing [LCP](https://web.dev/lcp/). Responsive images ensure that the browser downloads an appropriately sized image for the current viewport, reducing initial page weight and improving performance.

***

## How

### How responsive images work with `srcset` and `sizes`

The `srcset` attribute provides multiple image options at different widths. The `sizes` attribute tells the browser which option to use based on layout.

```html
<img
  src="image-800.jpg"
  srcset="
    image-400.jpg   400w,
    image-600.jpg   600w,
    image-800.jpg   800w,
    image-1000.jpg 1000w
  "
  sizes="(min-width: 1000px) 900px, calc(100vw - 2rem)"
  alt="Product"
/>
```

The browser:

1. Checks the current layout width.
2. Evaluates the `sizes` attribute to determine the image's display size in the current layout.
3. Checks the device's pixel density, such as 2x for Retina screens.
4. Selects the smallest image from `srcset` that fits the required size.
5. Downloads only that one image.

### The recommended Shopify `image_tag` implementation

Shopify's [`image_tag`](https://shopify.dev/docs/api/liquid/filters/image_tag) Liquid filter generates responsive images with proper `srcset`, `sizes`, and dimensions:

```liquid
{{ product.featured_image
  | image_url: width: 1000
  | image_tag:
      widths: '400, 600, 800, 1000',
      sizes: '(min-width: 1000px) 900px, calc(100vw - 2rem)'
}}
```

This generates a complete responsive image with:

* A `srcset` at the specified widths.
* Automatic `height` and `width` attributes, which prevent [CLS](https://web.dev/cls/).
* [Shopify CDN](https://shopify.dev/docs/storefronts/themes/best-practices/performance/use-shopify-cdn) URLs with automatic format conversion.

### Common mistakes

Too many widths in `srcset`:

* Hurts caching effectiveness.
* The browser has to evaluate more options.
* Four to six widths are usually sufficient.
* You don't need a perfectly sized image for every pixel.

Wrong `sizes` attribute:

* The browser downloads the wrong image.
* It might download the largest image, wasting bandwidth.
* It might download the smallest image, which looks pixelated.
* Use the Responsive Image Linter extension to check.

No `sizes` attribute:

* The browser defaults to downloading the largest image.
* It wastes bandwidth on mobile.
* LCP is slower.

### Getting `sizes` right

The `sizes` attribute is notoriously difficult. Use the [Responsive Image Linter](https://chromewebstore.google.com/detail/responsive-image-linter/mnddginionlghpbkfadlgdoaoemnahga) Chrome extension:

1. Install the extension.
2. Put any value in the `sizes` attribute.
3. The extension calculates the correct value.
4. Update your code.

Keep the `srcset` suggestions reasonable. You don't need a perfectly sized image for every possible width. Fewer widths improve caching.

### Let the browser work out `sizes` for lazy-loaded images

For images with `loading="lazy"`, set `sizes` to `auto` instead of writing a breakpoint list. The browser uses the image's own layout width to pick a source, so the value can't drift out of sync with your CSS:

```liquid
{{ product.featured_image
  | image_url: width: 1000
  | image_tag:
      loading: 'lazy',
      widths: '400, 600, 800, 1000',
      sizes: 'auto'
}}
```

Shopify injects a polyfill for browsers that don't support `sizes="auto"` natively, so it's safe to use today.

**Caution:**

`auto` applies only to images with `loading="lazy"`. Eager images, including the LCP image, still need an explicit `sizes` value, because the browser has to pick a source before layout runs. Never lazy-load the LCP image to get `auto`: the lazy-loading delay costs far more than an imperfect `sizes` value.

***

## Examples

### Special considerations for carousels, slideshows, and grids

Components that contain many images require careful implementation to avoid hurting performance.

* **Load only what's needed**: Don't render `<img>` tags for images that aren't visible. For a carousel, render `<img>` tags only for the first few images, and use JavaScript to add new `<img>` tags as the user navigates through the carousel. See [Limit pagination depth](https://shopify.dev/docs/storefronts/themes/best-practices/performance/limit-pagination-depth) for detailed carousel implementation patterns.
* **Prioritize visible images**: Make sure the first, visible image in a slideshow or grid loads eagerly with `loading="eager"`, and has `fetchpriority="high"` if it's the LCP element. All other non-visible images should use `loading="lazy"`.

***

## Testing

* **[Responsive Image Linter](https://chromewebstore.google.com/detail/responsive-image-linter/mnddginionlghpbkfadlgdoaoemnahga)**: A Chrome extension that helps you validate and generate correct `sizes` attributes.
* **Performance panel, Insights tab**: Run a measurement to see whether **Image sizes are too large** is flagged as an optimization opportunity.
* **[Chrome DevTools Network panel](https://developer.chrome.com/docs/devtools/network)**: Verify that the correctly sized image downloads at different viewport sizes.
* **[Device Mode](https://developer.chrome.com/docs/devtools/device-mode)**: Test at different viewport sizes, such as mobile, tablet, and desktop, and compare the file sizes of images being loaded.

***

## References

* [`image_tag`](https://shopify.dev/docs/api/liquid/filters/image_tag) filter
* [`image_url`](https://shopify.dev/docs/api/liquid/filters/image_url) filter
* [`product.featured_image`](https://shopify.dev/docs/api/liquid/objects/product#product-featured_image)
* [Responsive images on Shopify with Liquid](https://performance.shopify.com/blogs/blog/responsive-images-on-shopify-with-liquid)
* [Optimizing images for performance on Shopify](https://performance.shopify.com/blogs/blog/optimizing-images-for-performance-on-shopify)
* [Demo page: Liquid image\_tag demo](https://performance.shopify.com/pages/liquid-image_tag-demo)
* [Prevent image layout shift](https://shopify.dev/docs/storefronts/themes/best-practices/performance/prevent-image-layout-shift)
* [Never lazy-load the LCP image](https://shopify.dev/docs/storefronts/themes/best-practices/performance/never-lazy-load-lcp-image)
* [Mark the LCP image with `fetchpriority="high"`](https://shopify.dev/docs/storefronts/themes/best-practices/performance/set-fetchpriority-high-on-lcp-image)

***
