Responsive Product Images: srcset and sizes

Most stores compress their product photos, then ship the same 2000px file to a phone anyway — here is how to serve the right pixels to the right screen.

|image optimization e-commerce SEO page speed product photography

Serving a 2000px product photo to a 390px phone screen wastes roughly 96% of the bytes you just paid to download. The image looks fine, your compression settings look fine, and your Largest Contentful Paint is still terrible. This is the single most common product image performance bug in e-commerce, and it is invisible in every audit that only checks file format and quality settings.

Responsive product images fix it at the delivery layer. Instead of one file per photo, you publish a handful of sized variants and let the browser pick — using the srcset and sizes attributes to describe what is available and how big the image will actually render. Combining that with a modern format cuts total image payload by 60-70% compared to shipping a single full-size JPEG, according to 2026 implementation benchmarks.

This guide covers what to generate, how to write the attributes correctly, how many variants are worth the storage, and the specific mistakes that quietly cancel out the win.

Why compression alone does not fix product image weight

There are three separate levers on product image weight, and most teams only pull one of them.

LeverWhat it controlsTypical status
FormatAVIF vs WebP vs JPEG encoding efficiencyUsually handled
QualityCompression level within that formatUsually handled
DimensionsWhich pixel size the device actually receivesUsually ignored

Format and quality are multiplicative savings on a file you may not need at that size in the first place. Dimensions are the big one, because image weight scales with area, not width. Halving the width of a delivered image quarters its pixel count.

96%Pixels wasted serving 2000px to a 390px phone
60-70%Payload cut from responsive delivery plus AVIF
4xWeight increase from doubling image width

If you have already worked through format selection and compression settings, responsive delivery is the remaining lever — and usually the largest one left.

How srcset and sizes actually work

The two attributes answer two different questions, and mixing them up is the root of most broken implementations.

srcset is the menu: a comma-separated list of files with their intrinsic pixel widths, marked with a w descriptor. sizes is the layout hint: it tells the browser how wide the image will render at a given viewport, before the browser has parsed your CSS. The browser combines the two with the device pixel ratio and picks a file.

<img
  src="/products/kettle-800.jpg"
  srcset="/products/kettle-400.jpg 400w,
          /products/kettle-800.jpg 800w,
          /products/kettle-1200.jpg 1200w,
          /products/kettle-2000.jpg 2000w"
  sizes="(max-width: 768px) 100vw, 50vw"
  width="2000" height="2000"
  alt="Stainless steel pour-over kettle, side view">

Read the sizes value as a rule list: on viewports up to 768px the image fills the full viewport width; above that it fills half. A phone at 390px CSS width with a 2x display needs about 780 real pixels, so it takes the 800w file. A desktop at 1440px rendering at half width needs 720, and also takes 800w. The 2000w variant only ships to large or high-density screens that can use it.

The most common bug

A default sizes="100vw" left in place on an image that renders at 50vw makes every device request a file roughly twice as wide as needed — quadrupling the bytes. The image still looks correct, so nothing flags it. Check sizes against your actual grid, not against your template's default.

Keep src populated with a mid-sized variant as the fallback, and always set width and height attributes. Those two attributes let the browser reserve layout space before the file arrives, which is what prevents Cumulative Layout Shift as your gallery loads.

Choosing your variant ladder

The practical question is how many sizes to generate. Every extra variant multiplies storage, processing time and cache entries across your whole catalog — a 5,000-SKU store with 6 photos each is 30,000 source images before you generate anything.

Four variants is the sweet spot for most catalogs: 400, 800, 1200 and 2000 pixels wide. That ladder covers phones at 1x and 2x, tablets, standard desktop grids and zoom views, with roughly a 1.5-2x step between rungs. Steps smaller than that produce variants the browser rarely distinguishes between; steps larger than 2x mean devices routinely over-download.

Where each variant gets used (typical apparel catalog traffic)
400w
12%
800w
48%
1200w
27%
2000w
13%

The distribution matters for a second reason: it tells you which variant to optimise hardest. On a mobile-majority catalog the 800w file is your real product image. If your art direction, crop and colour decisions are being validated on a 2000px desktop preview, you are reviewing a file that under half your traffic ever sees.

Two adjustments worth making. First, thumbnails and grid tiles deserve their own narrower ladder — a category page tile that never renders above 400px does not need a 1200w entry in its srcset at all. Second, if you support pinch-to-zoom on the product detail page, keep the 2000w variant regardless of traffic share; that is exactly the moment a shopper is inspecting fabric texture or stitching, and a soft image there costs you the sale.

Generating variants without multiplying your production work

Responsive delivery only pays off if generating the ladder is automatic. If a person is exporting four sizes per photo by hand, the system will drift within a quarter — someone will skip the 400w on a rush drop, and the fallback behaviour will hide it.

Manual export

  • Four exports per photo, per SKU
  • Naming conventions drift between people
  • Re-shoots require the whole ladder regenerated
  • Missing variants fail silently
  • Scales linearly with catalog size

Automated pipeline

  • One master file per photo
  • Derivatives generated on request or at upload
  • Consistent naming by construction
  • Re-shoot replaces the master only
  • Catalog size is not the constraint

There are three common architectures. An image CDN generates derivatives on the fly from URL parameters, which is the lowest-effort option and handles format negotiation at the same time. Build-time generation suits smaller, stable catalogs where images ship with the site. Platform-native pipelines — Shopify's image transformation parameters being the obvious example — already do this for you, and the job is mostly making sure your theme emits a correct sizes value rather than a hardcoded URL.

Whichever you pick, the rule is that only one file per photo is authored. Everything downstream is derived. That principle also applies upstream: if your product imagery is produced or retouched through an automated pipeline — the approach AI product photography tools like Retouchable take — the master should land in your DAM at full resolution and let the delivery layer size it, rather than exporting web-sized finals that can never be re-derived upward.

Pro Tip

Store masters at least as wide as your largest variant plus headroom — 2400-3000px for a 2000w ladder. Upscaling a web-sized final later never recovers the detail, and zoom views are where that shows first.

The LCP interaction: eager, lazy and fetchpriority

Responsive images and Largest Contentful Paint are tightly coupled, and getting the loading hints wrong wastes the work you just did.

On a product detail page, the main product image is almost always the LCP element. It should be loaded eagerly with an explicit priority hint:

<!-- Hero / main product image -->
<img srcset="..." sizes="..." loading="eager" fetchpriority="high" ...>

<!-- Gallery thumbnails, below-fold, related products -->
<img srcset="..." sizes="..." loading="lazy" ...>
Image roleloadingfetchpriority
Main product image (LCP)eagerhigh
Gallery thumbnailslazyauto
Below-fold detail shotslazyauto
Related product tileslazyauto

Applying loading="lazy" to the hero image is a guaranteed LCP regression — the browser defers the request until layout confirms the image is in view, adding a round trip to your most important asset. Blanket "lazy load everything" plugins do exactly this, which is why product pages sometimes get slower after an optimisation pass.

The sizes attribute matters here too. The browser's preload scanner acts on srcset and sizes before CSS is parsed, so an accurate sizes value means the correct file starts downloading in the first few milliseconds of the page. An inaccurate one means the browser either fetches a heavier file or, worse, fetches twice. For the broader picture on measuring this, see our guide to product image LCP and Core Web Vitals.

Verifying it works, and the five failure modes

Responsive images fail silently by design — the wrong variant still renders a correct-looking image. You have to check deliberately.

The fastest verification: open a product page in DevTools, set the network panel to show the Resource column, and throttle to a mobile viewport. Look at which file was actually requested and compare it to the rendered display size. Chrome's Elements panel shows "intrinsic" versus "rendered" dimensions on hover — if intrinsic is more than about 2x rendered, you are over-serving.

The five failure modes worth auditing across a catalog:

  1. Stale sizes after a redesign. The grid changed from three columns to four; the sizes value did not. Every tile now over-downloads.
  2. Missing variants falling back to src. If a 400w derivative failed to generate, the browser uses what is available. Payload silently rises for the devices that needed it most.
  3. Lazy loading on the LCP image. Covered above, and the most damaging single mistake.
  4. CSS overriding the assumed layout. A container max-width that sizes does not account for means the browser reserves for a wider render than ever happens.
  5. Absent width and height attributes. No reserved space, layout shift as each gallery image lands, and a CLS score that degrades on slower connections.

Run this check on your three highest-traffic templates rather than the whole site — product detail, category grid and search results will surface essentially every mistake in the codebase. And re-run it after any theme or grid change, because sizes is the one attribute that goes stale without anything breaking. A quarterly pass alongside a broader product image catalog audit is usually enough to keep it honest.

Frequently Asked Questions

How many image variants should I generate per product photo?

<p>Four is the practical sweet spot for most e-commerce catalogs: 400, 800, 1200 and 2000 pixels wide. That gives roughly a 1.5-2x step between rungs, which covers phones at 1x and 2x pixel density, tablets, desktop grids and zoom views. Smaller steps create variants the browser rarely distinguishes between while multiplying your storage and cache entries; larger steps mean devices routinely download more than they need. Grid thumbnails that never render large can use a shorter ladder of just the two narrow variants.</p>

What is the difference between srcset and sizes?

<p>They answer different questions. <code>srcset</code> lists which files exist and how wide each one is in pixels, using the <code>w</code> descriptor. <code>sizes</code> tells the browser how wide the image will actually render on the page at a given viewport width. The browser combines your <code>sizes</code> value with the device pixel ratio to calculate the pixel width it needs, then picks the smallest file in <code>srcset</code> that satisfies it. Getting <code>srcset</code> right but leaving <code>sizes</code> at a default of 100vw is the most common implementation error, and it typically doubles the delivered image width.</p>

Do responsive images replace using WebP or AVIF?

<p>No — they stack. Format choice and responsive delivery are independent levers, and the savings multiply. AVIF is more efficient than JPEG at the same dimensions, but that efficiency applies to whatever pixel dimensions you ship, so an oversized AVIF is still oversized. Reported benchmarks put the combination of responsive delivery plus AVIF at a 60-70% payload reduction against a single full-size JPEG. Most image CDNs handle both at once, negotiating format via the Accept header while sizing via URL parameters.</p>

Will responsive images hurt my image SEO?

<p>No, provided the variants are genuinely the same image at different sizes. Google indexes the image referenced in <code>src</code> and understands <code>srcset</code>, and alt text, filenames and structured data all continue to work normally. The performance improvement is a mild positive signal, since page experience factors into ranking. The one thing to avoid is serving meaningfully different crops through <code>srcset</code> — that is art direction, and it belongs in a <code>&lt;picture&gt;</code> element with explicit media conditions instead.</p>

Does Shopify handle responsive product images automatically?

<p>Shopify generates sized derivatives through its image transformation parameters, so the variants exist without you exporting them. What is not automatic is the <code>sizes</code> attribute — that depends on your theme, and themes frequently carry a generic value that does not match a customised grid. If you have changed column counts, container widths or the product gallery layout, check what <code>sizes</code> your templates emit before assuming delivery is optimal. The variants being available does not mean the right one is being requested.</p>

Start from a master worth resizing

Retouchable produces full-resolution product images your delivery pipeline can size down to every breakpoint — without a manual export for each one.

Try Retouchable Free No credit card required