On a typical page, images are the majority of the bytes. Not the JavaScript everyone worries about, not the fonts — the pictures. Which means image work is usually the highest-return performance work available, and it is also the work most often done in the wrong order.

Advertisement: Kinsta managed WordPress hosting, free for the first 30 days

Advertisement. We earn a commission if you sign up through this link, at no extra cost to you.

There are six separate decisions here and they interact. Do them in this sequence and each one makes the next easier.

Why this is where the money is

The Largest Contentful Paint element — the thing Google measures to decide whether your page felt fast — is an image on most pages. A hero photo, a product shot, an article header. If that image is slow, your LCP is slow, and Google wants it under 2.5 seconds.

The cost is not only technical. A visitor on a phone with a weak signal is watching an empty rectangle while a 4 MB photograph arrives. They do not know it is a photograph. They know the page is broken, and they leave before your headline renders.

The reason this problem is so common is that nothing warns you about it. You upload a picture straight from a camera, it looks correct on your desktop, and the 4 MB never announces itself.

1. Format

Start here, because it is the single largest reduction available and it requires no design decisions.

WebP is roughly 25 to 35 percent smaller than JPEG at equivalent visual quality, and it has been supported in every current browser since Safari 14 in 2020. There is no longer a compatibility argument against it.

AVIF goes further — commonly around half the size of an equivalent JPEG — and is now supported across Chrome, Firefox and Safari 16 onward. Encoding is slower, which matters for a build pipeline and not at all for a WordPress upload.

The old formats still have their places. PNG for images that need genuine lossless transparency or sharp-edged graphics. SVG for logos, icons and diagrams — infinitely scalable and usually a fraction of the size. JPEG as the fallback for anything that has to work in an ancient client, like an email.

WordPress has handled WebP since 5.8 and AVIF since 6.5. Conversion plugins — Imagify, ShortPixel, EWWW, Converter for Media — will convert your existing library and serve modern formats with automatic fallback. Pick one, run it over the media library once, and a large share of this problem disappears without you touching a page.

Doing it by hand, the picture element gives you explicit control:

<picture>
  <source srcset="hero.avif" type="image/avif">
  <source srcset="hero.webp" type="image/webp">
  <img src="hero.jpg" alt="..." width="1200" height="630">
</picture>
A hero image delivered at 2,560 pixels and displayed at 793The largest contentful paint element on a real shop homepage is delivered 2,560 pixels wide and rendered in a 793 pixel slot, 3.2 times more pixels than the layout uses.793 px displayed1,767 px of width never rendereddownloaded, decoded, resized, discarded2,560 px deliveredThis image is also the LCP element, so its size sets the page’s Largest Contentful Paint.On the same page, 40 of 43 images carry no width or height attribute at all.
The hero image on a real cosmetics shop, measured September 2026. Serving it at the width the layout actually uses is a one-setting change; it is also the single largest available improvement to that page’s LCP.

2. Compression

Format is the container; compression is how hard you squeeze what goes in it.

For photographs, quality 75 to 85 is the range where almost nobody can see the difference from the original and the file is a fraction of the size. Below 70 you start seeing artifacts in gradients — skies and skin are where it shows first.

Strip the metadata while you are there. A camera JPEG carries EXIF data, color profiles and sometimes a thumbnail of itself, which can be tens of kilobytes of nothing anyone will ever read.

Every optimization plugin does both automatically on upload. The important part is turning it on before you bulk-upload a library, because retrofitting means reprocessing everything.

3. Serve the size that is actually displayed

This is the one that produces absurd numbers. A 3000-pixel-wide photograph displayed in a 300-pixel-wide thumbnail slot means the browser downloaded roughly a hundred times more data than it used, then spent CPU resizing it.

The fix is responsive images, and WordPress already does this for you. On upload it generates several sizes and writes them into a srcset so the browser can choose:

<img src="photo-1024x683.jpg"
     srcset="photo-300x200.jpg 300w,
             photo-768x512.jpg 768w,
             photo-1024x683.jpg 1024w,
             photo.jpg 1600w"
     sizes="(max-width: 768px) 100vw, 50vw"
     width="1024" height="683" alt="...">

Where this breaks is themes and page builders that output a bare src with the full-size image, ignoring the generated sizes entirely. Check by opening a page with a small image on it, inspecting the element, and comparing the intrinsic size the browser reports against the displayed size. A large gap is wasted download.

Two related habits worth adopting: set a sensible maximum upload dimension so nobody uploads a 6000-pixel image in the first place, and delete unused generated sizes — plugins and themes register their own, and a media library can quietly hold eight variants of every file.

4. Always set width and height

An image without dimensions is a hole of unknown size. The browser lays out the text, then the image arrives, then everything below it jumps down the page. That jump is Cumulative Layout Shift, and it is the reason you have clicked the wrong thing on a news site.

The fix is two attributes:

<img src="photo.jpg" width="1200" height="800" alt="...">

Modern browsers compute the aspect ratio from these and reserve the space before the file arrives. The values do not need to match the displayed size — CSS still controls that — they need to describe the correct ratio.

WordPress has added these automatically since 5.5. Where they go missing is hand-written HTML in a custom block, images injected by JavaScript, and background images in CSS, which cannot reserve space at all and need a sized container or an aspect-ratio rule.

Also worth reserving space for: ad slots, embedded video, and anything that loads late and pushes content around. Layout shift is not only an image problem, but images are where it usually starts.

5. Lazy loading, and what not to lazy load

Lazy loading defers images until they are about to enter the viewport. On a long page with twenty images, it means the browser fetches the three you can see instead of all twenty. One attribute:

<img src="photo.jpg" loading="lazy" width="800" height="600" alt="...">

WordPress has done this automatically since 5.5, and no JavaScript library is needed any more. If your site still loads a lazy-loading script from the pre-native era, removing it is a small free win.

The mistake that matters: never lazy load the hero image. Lazy loading tells the browser the image is not urgent, which is precisely wrong for the one image that defines your LCP. Deferring it can add a second or more to the metric — this is one of the most common ways a well-intentioned performance change makes a site measurably slower.

WordPress has been smart about this since 5.9, skipping lazy loading on the first images on the page. Aggressive lazy-loading plugins configured to defer everything will happily override that, so if you have one, check what it does to the top of the page.

6. Prioritize the hero

The opposite problem: the one image that must arrive first is queued behind stylesheets, fonts and scripts, because the browser has no way of knowing it matters.

Tell it:

<img src="hero.webp" fetchpriority="high" width="1200" height="630" alt="...">

Since WordPress 6.3 this is applied automatically to the image WordPress believes is the LCP element. Its guess is usually right and occasionally not — a slider or a builder-rendered header can confuse it.

For an image that is discovered late — a CSS background, or something rendered by JavaScript — a preload hint in the head starts the download before the parser reaches it:

<link rel="preload" as="image" href="hero.webp" fetchpriority="high">

Use this sparingly. Preloading is a claim that something is more important than everything else, and preloading five things is the same as preloading nothing.

The way to verify any of this: run the page through PageSpeed Insights and read the LCP element it reports. If it is not the image you expected, that is the finding.

Image CDNs

An image CDN sits between your library and the visitor and does formats, sizing and compression on the fly, at edge locations near the user. Cloudflare Images, Cloudinary, imgix, Bunny Optimizer, and Jetpack’s free Site Accelerator all do a version of this.

The honest case for one: if you have thousands of images, an international audience, or a team that will keep uploading unoptimized files, a CDN solves the problem permanently and removes the discipline requirement.

The honest case against: for a modest site on decent hosting with a general CDN already in front of it, converting the library to WebP once and letting WordPress handle sizes gets you most of the same result for no monthly fee. Solve it with process before you solve it with a subscription.

The other reason to care: alt text

Every image needs an alt attribute — describing the image for screen readers, or empty (alt=””) if it is purely decorative. It is the accessibility baseline and it is a legal requirement in a growing number of places. It is enough of a subject on its own that it has its own article; the point here is that it belongs in the same pass as everything above, because you are already touching every image.

Doing it in the right order

On an existing site, this sequence gets the most improvement for the least risk:

  1. Install an optimization plugin and bulk-convert the library to WebP or AVIF. Largest single reduction, no page edits.
  2. Check the hero image on your most important templates: not lazy loaded, has fetchpriority, has dimensions. This is where LCP is won or lost.
  3. Find images served larger than displayed — PageSpeed Insights flags them under “properly size images”. Usually a theme or builder problem with one fix that covers many pages.
  4. Confirm width and height everywhere, especially in custom blocks.
  5. Set an upload size limit so the problem stops recurring.
  6. Consider an image CDN only if the first five did not get you there.

Measure before and after with PageSpeed Insights on the same URL, and look at LCP rather than the overall score. The score moves for many reasons; LCP tells you whether the image work actually did something.

The short version

Convert to WebP or AVIF, compress at quality 80, serve the size you display, always set width and height, lazy load everything except the hero, and give the hero high fetch priority. Six things. Most sites do two of them.

Working through this list on your own site and would rather not? That is what an Expert Web Audit is for.

Advertisement: Kinsta managed WordPress hosting

Advertisement. We earn a commission if you sign up through this link, at no extra cost to you.

Leave a Reply

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