Mantys Core
Mantys CorePerformance guideCluster: Images5 min

Why does PageSpeed Insights still say “Properly size images” when I have a srcset?

The one-sentence summary: srcset offers the browser a list of sizes, but it is the sizes attribute that tells it which one to pick. If sizes is missing, wrong, or ignored, the browser downloads the largest image in the list, and PageSpeed flags it, srcset or not.

You did everything you were told. Your images have a well-filled srcset, several widths generated, WebP (a next-gen image format, lighter than JPEG or PNG). And yet the PageSpeed Insights audit still shows Properly size images, with several hundred KB listed as savings.

This is not a PageSpeed bug. It is a very common misunderstanding of how responsive images actually work. Let us clear it up for good.

What srcset does, and what it does not

Take a typical case:

HTML
<img
  src="photo-1200.jpg"
  srcset="photo-400.jpg 400w,
          photo-800.jpg 800w,
          photo-1200.jpg 1200w,
          photo-2000.jpg 2000w">

Many people think the browser will “pick the most suitable one”. In reality, srcset on its own is just a menu. It says: here are the available sizes and their real width in pixels. It says nothing about the space the image takes up in your page.

Without information about the display width, the browser applies a default: sizes="100vw" (vw = viewport width, the width of the window), meaning “assume the image spans the full width of the window”. And that is where it all goes wrong.

Key infos
  • srcset = a list of available images, nothing more.

  • It is sizes that tells the browser which size to take.

  • Without sizes, the browser assumes “full screen” and loads too big.

The real cause: the sizes attribute (and the screen-density trap)

The calculation the browser makes is simple:

display width (from sizes) × screen pixel density (the DPR, for Device Pixel Ratio) = target width in pixels → it takes the first image in the srcset ≥ this target.

Let us run two scenarios on a 400px-wide mobile with a Retina screen (DPR = 2, the norm on mobile):

Scenario A: sizes missing (default 100vw)

  • Assumed width: 400px (100vw)

  • × DPR 2 = 800px target

  • But if your image is actually only 180px wide on screen (a thumbnail in a grid), the browser still downloads the 800w variant. 4× too heavy.

Scenario B: correct sizes

  • sizes="(max-width: 600px) 180px, 300px"

  • Real width: 180px × DPR 2 = 360px target

  • The browser takes the 400w variant. Weight divided by 4-5.

The conclusion that hurts: a srcset without a correct sizes is almost useless. The browser, when in doubt, takes too big, and PageSpeed sees it.

The DPR is the factor everyone forgets: on mobile most screens are DPR 2 or 3. An image displayed at 200 physical px needs a 400 to 600px source. That is not waste; beyond that, it is.

Key infos
  • The browser computes: displayed width × DPR = size to download.

  • On mobile (DPR 2-3), a 200px image needs a 400-600px source, no more.

  • A wrong or missing sizes blows up this calculation, so PageSpeed sees the excess.

The WordPress case: the default sizes is often wrong (the #1 cause in practice)

If you are on WordPress, there is a good chance your problem comes from here, and it is not a missing sizes, but an automatic and wrong sizes.

WordPress generates the srcset and a sizes on its own. But the value it puts by default looks like:

HTML · generated by WordPress
  sizes="(max-width: 1024px) 100vw, 1024px"

In other words: “this image spans the full content width”. That is true for a full-width article image. It is wrong the moment the image lives in a grid, a column, a sidebar, a card, a gallery, which is most cases. The result: sizes announces a width far larger than reality, the browser loads too big, and PageSpeed sees it.

Worse: many page builders (Divi, Elementor…) and themes do not adjust this sizes to the real column. So you have a flawless srcset, well-generated variants… and a sizes that sabotages them. It is the most frequent cause of the “Properly size images” complaint on a WordPress site, and the one you never think to check precisely because “WordPress handles it”.

Key infos
  • WordPress sets a default sizes of the type “I span the full content width”.

  • True at full width, wrong in a grid / column / sidebar, so it over-downloads.

  • Page builders and themes rarely fix this sizes, the #1 cause in practice.

Diagnose in 30 seconds (without guessing)

Open Chrome DevTools, Elements tab, hover over the <img> tag. Chrome shows:

  • Rendered size: the size at which the image is actually displayed.
  • Rendered aspect ratio and Intrinsic size: the size of the downloaded file.
  • Current source: which variant of the srcset was chosen.

The verdict is immediate. If you see a rendered size of 180px but the current source is photo-800.jpg, your sizes is missing or wrong. If the rendered size is 180px and the current source is photo-400.jpg, you are correct: 400 = 180 × DPR 2, rounded up to the next step.

You can also use the Network tab: sort by size, reload, and watch which variant goes over the wire.

The generic fix (what a developer does by hand)

a. Write a sizes that matches your real layout

This is the heart of the problem. sizes must reflect the real width of the image, the one imposed by your CSS, at each breakpoint (the screen width at which the layout changes). Example for an image full-width on mobile but on 3 columns on desktop:

HTML
  sizes="(max-width: 600px) 100vw,
         (max-width: 1024px) 50vw,
         33vw"

b. Generate the right variants

No point having a 2000w variant if your image never exceeds 600px on screen. And conversely: provide the steps that cover your real widths × DPR (up to 2, sometimes 3).

c. Do not forget width and height

They do not change the weight, but they prevent CLS (Cumulative Layout Shift, content that jumps while loading), PageSpeed’s other recurring complaint.

The case where even a perfect sizes is not enough

Some elements carry no srcset at all: sliders (Nivo, Swiper, many themes), CSS background images, or any markup that outputs a raw <img src="...">. There, there is literally nothing to rewrite: no optimization plugin can act, because there is no srcset/sizes to fix. It is a separate problem (images without srcset), which calls for a different approach than the one described here.

Key infos
  • Write a sizes faithful to your layout at each breakpoint.

  • Generate only the useful variants (up to your max width × DPR).

  • Add width/height against CLS.

  • Edge case: images without srcset (sliders, backgrounds) cannot be fixed until the markup exposes something.

Why it is so painful to maintain by hand

Writing the right sizes assumes knowing, for each image and each breakpoint, the real CSS display width. On a 5-page brochure site, that is doable. On a site with dozens of templates, grids that change, editorial content… it is unmanageable, and it drifts out of sync with every redesign.

With Mantys Core

This is exactly the problem Mantys Core solves by measuring rather than guessing:

  • it renders the page like a real browser and measures the actually displayed width of each image, at each breakpoint;

  • it rewrites sizes from that measurement: no more default 100vw, no more over-download;

  • it generates the useful variants (and their WebP version) aligned with those real widths;

  • and for images without srcset (sliders, raw sources), it applies a substitution toward the measured variant, the case classic tools leave aside.

The concrete result: the “Properly size images” complaint disappears because the browser finally downloads the right size, the one your layout actually asks for.

In summary

  • srcset = a menu of sizes. sizes = the choice instruction. Without the latter, the former is almost useless.
  • The mobile DPR (×2, ×3) doubles or triples the target width, hence the over-download.
  • Diagnose with Rendered size vs Current source in the DevTools.
  • The fix = a sizes faithful to your real layout + the right variants. By hand it is tedious and fragile; measured and automated, it is reliable.
My AccountGet License →