/ โ† Page Speed Fixes / Images and Load Speed
In this guide
  1. Four ways images cost load time
  2. Measuring the image share of your page
  3. The first few seconds: who gets the bandwidth
  4. Images the browser finds too late
  5. The fix, step by step
  6. Decoding, huge dimensions and animation
  7. Platform notes
  8. Edge cases
  9. Keeping image cost under control
  10. Questions and answers

Four ways images cost load time

When a speed report blames images, it can mean several different things. Each one has a different fix, so it is worth separating them before changing anything.

CostWhat happensWhat it hurts
BytesLarge files take a long time to download, especially on mobile dataLargest Contentful Paint if the big file is the main image; total load time and data use otherwise
CompetitionMany images download at once and share the same bandwidth as the files that matterThe main image and critical files arrive later than they could
Late discoveryThe browser only finds an image after reading CSS or running JavaScriptThe main image starts downloading late, even if it is small
DecodingVery large pixel dimensions take time and memory to decode and scaleScrolling and responsiveness on low-end phones

File size problems have their own detailed guides: oversized image files covers compression and metadata, image format covers AVIF and WebP, and lazy loading covers the loading attribute. This page sits above those. It is about the share of the load that images take, the order they arrive in, and which of the detailed fixes to apply first.

๐Ÿ’ก A page can have perfectly compressed images and still be slowed by them, because twenty well-compressed thumbnails loading before the headline image still push that headline image back.

Measuring the image share of your page

Run the Page Speed Analyzer on each main template. It measures the page with real-user and lab data and lists the heaviest requests, along with total page weight and the number of requests. Note how many of the heaviest files are images and whether the element it names as slow is an image.

In Chrome DevTools

  1. Open the Network panel, tick Disable cache, choose a mobile throttling profile and reload.
  2. Click the Img filter. The status bar at the bottom shows the number of image requests and how much was transferred. Compare that with the unfiltered totals.
  3. Sort by the Waterfall column, so you can see which images start before the main content has finished loading.

A quick Console summary

After a fresh, uncached load, this snippet totals image bytes by who requested them, which separates HTML images from CSS backgrounds:

const imgs = performance.getEntriesByType('resource')
  .filter(r => /\.(avif|webp|jpe?g|png|gif|svg)(\?|$)/i.test(r.name));
const byType = {};
imgs.forEach(r => {
  byType[r.initiatorType] = (byType[r.initiatorType] || 0) + r.transferSize;
});
console.table(byType);
console.log(imgs.length + ' images, ' +
  Math.round(imgs.reduce((a, r) => a + r.transferSize, 0) / 1024) + ' KB');

Images served from another domain may show a transfer size of zero unless that server sends a Timing-Allow-Origin header. If your totals look too low, check the Network panel instead. The pattern-match on file extensions will also miss images served from URLs without an extension, such as some image CDNs.

What to write down

The first few seconds: who gets the bandwidth

Early in the load, the connection is shared between the HTML, stylesheets, scripts, fonts and images. Modern HTTP/2 and HTTP/3 connections can carry many files at once, but they still share the same bandwidth. Browsers try to put important files first, and they generally start images at a low priority until they know which ones are visible. That guesswork is where things go wrong.

Carousels and sliders

A hero carousel with five slides often requests all five full-width images at the start, even though only one can be seen. The other four take bandwidth from the one that matters. Make only the first slide load eagerly, and load the rest lazily or once the carousel starts moving. Better still, ask whether the carousel is needed at all; a single strong image is usually faster and clearer.

Priority hints

The fetchpriority attribute lets you tell the browser which image matters. Put fetchpriority="high" on the one image that is the main content of the first screen, and consider fetchpriority="low" on images that are visible but unimportant, such as later carousel slides or small decorative graphics near the top.

<img src="/img/hero-1200.webp" width="1200" height="600"
     alt="Freshly baked sourdough on a wooden board"
     fetchpriority="high">

<img src="/img/slide-2-1200.webp" width="1200" height="600"
     alt="Our shop counter" loading="lazy" fetchpriority="low">

Use high on one image, or two at most. Marking everything high is the same as marking nothing.

Icons and small graphics

A header with a dozen small PNG icons makes a dozen requests. Each is tiny, but together they add overhead and compete with the main image. Replace them with inline SVG or an SVG sprite, or with an icon font you already load, and the requests disappear.

Images the browser finds too late

The browser's preload scanner reads the HTML ahead of the parser and starts downloading images it can see in <img> tags straight away. It cannot see images that only exist in other places:

If the late image is the main content of the first screen, the fix is to put it in the HTML as a real <img> element, styled to cover its area with object-fit: cover. That usually looks identical to a background and loads much earlier. If you cannot change the markup, add a preload in the head:

<link rel="preload" as="image"
      href="/img/hero-1200.webp"
      imagesrcset="/img/hero-800.webp 800w, /img/hero-1200.webp 1200w, /img/hero-1800.webp 1800w"
      imagesizes="100vw"
      fetchpriority="high">

The imagesrcset and imagesizes attributes should match the image the page actually uses, otherwise the browser downloads one version for the preload and another for the page.

โš ๏ธ Do not preload images below the first screen. Preloads run at high priority and would recreate the competition problem this guide is trying to fix.

The fix, step by step

Step 1

Measure the image share of each template

Test your home page, a listing or category page, a product or service page and an article on a throttled mobile profile with the cache off. For each, note total image bytes, the number of image requests, the total page weight and whether the slowest element is an image. Templates where images make up most of the bytes, or where dozens of images load before scrolling, are where this work will pay off first, so start there rather than with the home page by habit.

Step 2

Rank images by when they load, not by size

Sort the Network panel by start time and look only at images that begin downloading before the main content has appeared. Those are the ones competing with the page's critical files. A heavy image far down the page that already loads lazily matters much less than a modest one that loads early for no reason. Mark each early image as needed on the first screen, visible but unimportant, or not visible at all without scrolling.

Step 3

Remove first-screen images that do no work

Go through the early images and ask what each one does for the visitor. Hidden carousel slides, a second logo for the mobile menu, decorative flourishes, social icons as separate PNG files and background textures are common candidates. Remove them, switch icons to inline SVG, or load extra slides only when the carousel moves. Every image you take out of the first seconds of the load gives more bandwidth to the ones that remain and costs nothing to maintain.

Step 4

Give the main image priority and demote the rest

Find the single image that forms the main content of the first screen and make sure it is not lazy-loaded. Add fetchpriority="high" to it. Give later carousel slides and minor visible graphics fetchpriority="low", and add loading="lazy" to everything below the first screen. Test again and check in the waterfall that the main image now starts near the top of the image requests rather than somewhere in the middle of them.

Step 5

Move late-found images into the HTML

If the main image is a CSS background or is inserted by a script, change the template so it is a normal <img> element with object-fit: cover, which the browser can find while reading the HTML. Where the markup cannot change, add a preload link in the head with matching imagesrcset and imagesizes values. Then check the waterfall again to confirm that the image now starts downloading alongside the stylesheets rather than after them.

Step 6

Match pixel dimensions to the display size

Compare each image's natural width with the width it is shown at on a phone and on a desktop. A 3000-pixel photo shown in a 400-pixel card wastes most of its bytes. Generate a few widths of each image and list them in srcset, with a sizes value that describes the real layout width, so each device picks a suitable file. Most content systems and image CDNs can create the widths automatically once you set them up.

Step 7

Cache images so repeat views cost nothing

Check the response headers of a few images. Images whose file names change when the picture changes, such as names containing a version or hash, can be sent with Cache-Control: public, max-age=31536000, immutable, so a returning visitor or someone browsing a second page downloads nothing. Images whose names stay the same when replaced need a shorter lifetime. If your host sends no caching headers at all, fix that at the server or CDN level.

Step 8

Set an image budget per template

Using your new measurements, write down a limit for each template, such as a maximum for total image bytes on first load and a maximum number of images before scrolling. Share it with whoever uploads content and whoever edits the theme. Check it whenever a template changes or a new section is added, and retest the templates monthly. A budget turns a one-off clean-up into a standard that stops the page from gradually getting heavy again.

Decoding, huge dimensions and animation

Downloading is not the end of an image's cost. The browser also has to decode it into pixels in memory, and scale it to the size it is shown at. For normal photos this is quick, but some cases are expensive on low-end phones:

The decoding="async" attribute hints that the browser may decode an image without holding up other rendering work. It is harmless on most images below the first screen, but it does not reduce the total work, so it is no substitute for sending sensibly sized files.

Platform notes

WordPress

WordPress generates several sizes of each upload and adds srcset automatically for images inserted through the editor. Recent versions also add fetchpriority="high" to an image they judge to be the main one and lazy-load others, but themes and page builders can override this, so check the output. Hero images set as section backgrounds in page builders are a very common source of late discovery. See WordPress images for the details.

Shopify

Shopify's image CDN can resize and convert images on request, so most speed gains come from the theme asking for sensible widths and marking the first product or banner image correctly. Shopify images covers the Liquid involved.

Next.js

The built-in image component generates sizes, lazy-loads by default and supports a priority setting for the main image, but it relies on you giving an accurate sizes value. See Next.js images.

Custom and static sites

You will need a build step or an image CDN to produce several widths and modern formats. The image CDN guide compares the options.

Edge cases

Keeping image cost under control

Images creep back because new content is added every week by people who never see a waterfall. The budget from step 8 is the main defence, backed by a few settings:

The Image Optimisation Guide explains the wider set of image checks, and the LCP guide goes deeper on the main image once you have cleared the competition around it.

Questions and answers

1. How do I know if images are what makes my page slow?

Load the page with the cache disabled and filter the Network panel to images. Compare image bytes and requests with the page totals, and check whether the largest element on the first screen is an image. If images make up most of the bytes, or the main image starts downloading late, images are a major cause. If the page is slow before any image starts, look at server response and render-blocking files first, because those delay everything, images included.

2. Should the main hero image be lazy-loaded?

No. Lazy loading tells the browser to wait until an image is near the viewport, and the browser can only work that out after layout. For an image that is already on the first screen, that wait simply delays it. Load the main image normally and consider adding fetchpriority high to it. Use lazy loading for images further down the page, where it saves bandwidth for the content visitors see first without them noticing any delay.

3. What does fetchpriority do, and is it safe to use?

It is an HTML attribute that tells the browser how important a resource is compared with others of the same type. Setting it to high on the main image asks the browser to fetch it sooner; setting it to low on unimportant images lets them wait. Browsers that do not support it simply ignore it, so it is safe to add. The main risk is overuse: if many images are marked high, the hint loses its value.

4. Why is my background image loading so late?

Because the browser does not know it exists until it has downloaded the stylesheet, built the page structure and worked out that an element uses that background. An image in an img tag is found almost as soon as the HTML arrives. If the background is the main visual on the first screen, change it to an img element that covers the area, or add a preload link in the head so the browser can start fetching it early.

5. How many images is too many on one page?

There is no fixed number. What matters is how many load before the visitor scrolls, and how many bytes they add up to on a phone. A long article with thirty lazily loaded images below the first screen can be fast, while a home page that loads eight slider images and a dozen icons up front can be slow. Count images that load without scrolling on each template and set your own limit based on what you measure.

6. Do WebP or AVIF fix slow images on their own?

They help, because they usually produce smaller files than JPEG or PNG at similar quality. They do not fix images that are far larger in pixels than needed, images that load before they are needed, or a main image that the browser finds late. Converting format is one of several fixes. Start with which images load and when, then reduce pixel dimensions, then change format, and you will get more from each step than from format alone.

7. Does image caching help first-time visitors?

Not directly. Browser caching only helps once a visitor has already downloaded an image, so it speeds up later pages and return visits. For first-time visitors, the gains come from sending fewer and smaller images and loading the important one first. A content delivery network does help first-time visitors, because it stores copies close to them and can resize images on the fly, which shortens the download even on the very first view.

See how much of your page is images

The Page Speed Analyzer measures your page with real-user and lab data, reports total page weight and requests, and names the heaviest files holding the page back, so you can see which images to deal with first.

Open Page Speed Fixes โ†’
๐Ÿ’ฌ Got a problem?
Related Guides: All Page Speed Fixes  ·  Oversized Image Files  ·  Fixing Slow LCP  ·  Image Optimisation Guide  ·  Learning Hub

About aiwebpageseo

aiwebpageseo.com is a data-driven SEO and AEO (Answer Engine Optimisation) platform providing a free suite of technical SEO tools. Rather than relying on AI-theorised assumptions, the platform analyses live URL performance, delivering objective diagnostics, page speed metrics, CLS debugging, and site crawl data alongside actionable technical tutorials.