Why WordPress Serves the “Wrong” Image Size (How srcset Actually Works)

•

I get some version of this question a lot: “why is WordPress serving a tiny, blurry image when I uploaded a huge one?” Every time I’ve dug into it, the answer is the same. WordPress isn’t choosing which image file to show you — your browser is, based on information your theme handed it. The “bug” is almost always a mismatched sizes attribute, not a broken upload.

Let me walk through what’s actually happening in the markup, because once you can read it, this stops being mysterious.

What WordPress actually outputs

When you insert an image in the block editor, WordPress doesn’t just output one plain <img src> tag. It outputs a whole set of image options for the browser to choose from, using something called srcset — short for “source set,” a list of the same image saved at several different sizes. Here’s what that looks like in the actual HTML:

<img src="https://example.com/wp-content/uploads/2026/09/photo-1024x683.jpg"
     srcset="https://example.com/wp-content/uploads/2026/09/photo-300x200.jpg 300w,
             https://example.com/wp-content/uploads/2026/09/photo-768x512.jpg 768w,
             https://example.com/wp-content/uploads/2026/09/photo-1024x683.jpg 1024w,
             https://example.com/wp-content/uploads/2026/09/photo-1536x1024.jpg 1536w,
             https://example.com/wp-content/uploads/2026/09/photo-2048x1365.jpg 2048w"
     sizes="(max-width: 1024px) 100vw, 1024px"
     alt="A photo" />

That srcset list tells the browser: “here are several versions of this image, each this many pixels wide — you pick.” Nobody is choosing one on the server. The browser looks at three things: how wide the visitor’s screen is, how sharp that screen’s pixels are, and the sizes attribute. Then it decides for itself which file to download. WordPress’s job ends at generating that list. The decision happens entirely on the visitor’s device.

The part everyone skips: the sizes attribute

The sizes attribute is the part that trips people up, so it’s worth slowing down on. In plain terms, it’s you telling the browser how wide the image will actually appear on the page, before the browser has downloaded anything or finished laying out the CSS. Think of it as a promise: “at this screen width, this image will take up this much space.”

The default value WordPress generates looks roughly like (max-width: {width}px) 100vw, {width}px. That assumes the image is shown at its full width and simply shrinks to fit the screen below that. It’s a reasonable generic guess. It’s also wrong the moment your theme places that image inside a sidebar, a three-column grid, a fixed-width card, or anything narrower than the full screen.

Here’s the failure mode I see constantly. An image sits in a 300px-wide card, but its sizes attribute still claims 100vw — the full screen. On a phone with a 390px screen and a sharp (3x density) display, the browser does the math as if the image will fill nearly the whole screen, multiplies that by the density, and downloads a huge file — for a box that’s actually only 300px wide. The image itself isn’t wrong. The size estimate WordPress gave the browser is wrong, so the browser over-fetches.

How to actually check this, not guess at it

You don’t need to guess which side of this is broken — your browser will tell you. Open DevTools (right-click the image and choose “Inspect,” or press F12), find the <img> tag, and look at its live srcset and sizes attributes in the Elements panel. Check the live version, not “view page source” — some themes and plugins rewrite these values with JavaScript after the page loads, so the raw source can be misleading. Then:

  • Check the actual rendered width of the image (the Computed panel shows this, or you can just measure the box on the page).
  • Compare that number to what sizes claims for the current screen width.
  • In the Network tab, filter by “Img” and reload the page — this shows you exactly which srcset candidate got picked, along with its real dimensions.

If the rendered width and the sizes claim roughly match, WordPress and the browser both did their job correctly, and the image just looks soft for another reason — heavy compression, upscaling, or a genuinely low-resolution original. If they don’t match, that’s the real bug, and it lives in your theme’s CSS or markup, not in WordPress’s image pipeline.

Fixing a genuinely wrong sizes attribute

Once you’ve confirmed sizes doesn’t reflect reality, don’t try to hand-edit it on every single image. Fix it at the source instead, using a WordPress filter called wp_calculate_image_sizes — a filter is just a hook that lets you change a value WordPress is about to output, in this case for every image in a given context at once.

Here’s what that looks like if you know images inside your .card layout always render at 320px, no matter the screen size:

function mytheme_fix_card_image_sizes( $sizes, $size, $image_src, $image_meta, $attachment_id ) {
    // Only touch images actually placed in card layouts.
    if ( is_admin() ) {
        return $sizes;
    }

    // Adjust this condition to however you detect the context --
    // e.g. checking a class passed through, or a specific template.
    if ( doing_filter( 'the_content' ) && has_post_thumbnail() ) {
        return '320px';
    }

    return $sizes;
}
add_filter( 'wp_calculate_image_sizes', 'mytheme_fix_card_image_sizes', 10, 5 );

A more common real-world case is a three-column grid that collapses to a single column on mobile. For that, a value tied to media conditions works better than one flat pixel number:

function mytheme_grid_image_sizes( $sizes, $size ) {
    return '(max-width: 600px) 92vw, (max-width: 1024px) 45vw, 30vw';
}
add_filter( 'wp_calculate_image_sizes', 'mytheme_grid_image_sizes', 10, 2 );

Match these breakpoints to your actual CSS media queries, not arbitrary numbers — that’s the whole point. The value in sizes is a promise to the browser, and the fix is simply making that promise true again. If you’d rather hand this off, this is a quick task for a developer since it just needs your theme’s real breakpoints plugged in. One thing worth knowing before you go looking for where to add this filter: block themes and classic themes handle template markup somewhat differently, so where this code lives can vary. If you’re not sure which kind you’re running, see my post on block themes versus classic themes for SEO.

One more thing worth checking

If your theme uses a CSS background-image instead of an actual <img> tag — common for hero banners — none of this applies. srcset and sizes only work on real <img> elements. Background images always load whatever single file you hardcoded in the CSS, at full size, regardless of screen width. That’s its own separate performance problem, worth solving with something like image-set() or a media-query-based background — but it isn’t a WordPress issue at all. If you’re chasing broader image-weight problems on your site, it’s also worth checking how many sizes WordPress generates per upload in the first place — see my post on trimming down unnecessary image sizes.

Bottom line: before assuming WordPress botched an image, check what sizes is actually claiming versus what your CSS actually renders. Nine times out of ten, that mismatch is the entire bug.

Frequently Asked Questions About WordPress Image Sizing

Why does my image look blurry on some pages but not others?

It’s usually because the sizes attribute is accurate on one page’s layout but not another. A theme often applies different CSS to the same image depending on where it’s placed — full-width in one template, inside a narrow card in another — and if the sizes value doesn’t update to match, the browser fetches the wrong file for that layout.

Do I need a developer to fix this?

For the diagnosis, no — anyone comfortable opening browser DevTools can compare the rendered width to the sizes value themselves. Actually writing the wp_calculate_image_sizes filter to fix it does require editing your theme’s functions file, so that part is worth handing to a developer if you’re not comfortable with PHP.

Will changing my sizes attribute break anything else on my site?

No, adjusting sizes only changes which existing image file the browser downloads — it doesn’t touch your content, your uploads, or any other setting. The worst case if you get a value wrong is that images look slightly softer or load slightly slower again, not that anything breaks.

Should I just upload smaller images to avoid this?

That fixes the wrong problem. WordPress already generates multiple sizes automatically specifically so the browser can pick a small one when appropriate. The issue here is that the browser is being told the wrong target size, not that the source image is too big.

Does this affect my SEO or page speed scores?

Yes, indirectly. If the browser is downloading images larger than it needs, that adds unnecessary load time, which tools like Google PageSpeed Insights will flag as an opportunity to “properly size images.” Fixing the sizes attribute is often the actual fix behind that warning.

Why does WordPress generate so many image sizes in the first place?

So it has options to offer the browser through srcset for different screen sizes and pixel densities. Not every one of those sizes is always useful, though, and pruning the list your site generates on upload is a related but separate optimization.

One response to “Why WordPress Serves the “Wrong” Image Size (How srcset Actually Works)”

Leave a Reply

Your email address will not be published. Required fields are marked *