Dimensions are the biggest lever by a wide margin
Serving a 4000-pixel photo into a 600-pixel column wastes roughly 97 percent of the downloaded pixels. No format choice and no compression setting recovers that.
Work out the largest size each image is genuinely displayed at, then double it if you are supporting high-density screens. A 600-pixel column needs 1200 pixels. A grid thumbnail displayed at 200 needs 400.
This one step routinely removes more page weight than every other optimisation combined, and it is the one most often skipped because the image looks fine either way.
Format second
WebP is the default for browser display: 25 to 35 percent smaller than JPEG at matched quality, with an alpha channel so it covers photos and logos alike.
AVIF saves another 20 to 30 percent beyond WebP where you can use it, at the cost of slower encoding. It is worth adding for a small number of high-impact images rather than a whole library.
Keep a JPEG fallback via the picture element for anything that might be viewed outside a browser context, and use SVG for logos and icons — it scales infinitely and is usually smaller than a single raster export.
Compression third
Quality 80 is the workhorse setting for web images. Going from 95 to 85 typically halves the file with no visible change; 85 to 75 removes another third with very little.
Set the level by the hardest image in your set — the one with the most sky or the smoothest gradient — because those band first.
Compress after resizing, never before. Compressing first spends bits describing pixels you are about to discard, and its artefacts get resampled into the final image.
Loading strategy fourth
This is where the remaining wins live once the files themselves are right.
- Set width and height attributes on every image so the browser reserves space and the page does not shift as images arrive
- Use loading=lazy on anything below the fold, and explicitly not on your hero image
- Add fetchpriority=high to the Largest Contentful Paint image so it is not queued behind less important requests
- Use srcset and sizes so phones download a phone-sized file rather than a desktop one
- Serve from a CDN with long cache headers and immutable filenames
Largest Contentful Paint is usually an image
On most content pages the LCP element is the hero image, which makes it the single most important asset on the page for Core Web Vitals.
Do not lazy-load it. Lazy loading defers the request until layout has determined the image is in view, which is precisely the delay you are trying to avoid on the one image that defines the metric.
Preloading it and setting fetchpriority high both help. So does making it smaller — an LCP image that is half the size arrives in half the time, and no amount of loading cleverness beats simply having less to download.
Layout shift is the other half
An image without dimensions occupies no space until it loads, then suddenly claims its full height and pushes everything below it down. That is Cumulative Layout Shift, and it is one of the most irritating things a page can do.
The fix is trivial: set width and height attributes, or a CSS aspect-ratio. The browser then reserves the correct space from the first paint.
This applies to anything that arrives late and takes space — embedded content, ad slots, and web fonts that change line height when they swap in.
Automate it
Doing this by hand for every image does not survive contact with a real site. Most content management systems and image hosts will generate multiple sizes and formats at upload and negotiate the right one per request.
If yours does, your job reduces to uploading a sufficiently large original and letting the pipeline handle the rest — and to not uploading a 12-megapixel photo where a 2000-pixel one would do.
If you are building the site yourself, a build-time image pipeline is worth the setup cost. Manual optimisation is done inconsistently and then abandoned.
Measure rather than assume
Run the page through Lighthouse or PageSpeed Insights and look specifically at the image recommendations: properly size images, serve in next-gen formats, and efficiently encode images. Each names the specific files and the specific saving.
Field data beats lab data. Lighthouse runs on a simulated connection; real users are on real networks with real devices, and the gap can be substantial.
Check the total transfer size of a page in your browser's network panel. If images are more than about 60 percent of it, they are where the remaining work is.
Frequently asked questions
What is the biggest win for image performance?
Correct dimensions. Serving a 4000-pixel photo into a 600-pixel column wastes 97 percent of the download, and no format or compression setting recovers that.
What quality should web images be?
Around 80. Going from 95 to 85 halves the file with no visible change; below 70 you start paying in visible damage.
Should I lazy-load all images?
No. Lazy-load below the fold, but never the hero image — that is usually your Largest Contentful Paint element and deferring it directly harms the metric.
Why does my page jump around while loading?
Images without width and height attributes occupy no space until they load, then push content down. Set dimensions or a CSS aspect-ratio.
Is WebP or AVIF better?
AVIF compresses better but encodes slowly and has narrower support outside browsers. WebP with a JPEG fallback is the practical default; add AVIF for a few high-impact images.
Do I need a CDN?
It helps for reach and caching, but it does not fix oversized images. Get the dimensions and format right first — a CDN serving 4 MB photos is still serving 4 MB photos.