# Image optimisation for page speed: the hero image and everything below it

Start with the hero image: it is often your Largest Contentful Paint. Give it priority, never lazy-load it, and size it for the first mobile viewport. Then make every other image cheap to ship and cheap to render.

Updated 2026-09-14 · Source: https://porteur.ai/guides/image-optimisation-for-page-speed

## Fix the hero image first

Your hero image often becomes the LCP element. It sets the first impression and the Core Web Vitals pass or fail. Treat it as a first-class request.

- Never use loading=lazy on the hero image.
- Add fetchpriority=high on the hero img.
- If it is a CSS background, preload it with a link rel=preload as=image and give it a high priority.
- Serve it in AVIF or WebP with a safe JPEG fallback when needed.
- Generate a responsive srcset and a sizes that matches your layout.
- Set explicit width and height so the box is reserved and does not shift.
- Place the img element in the HTML source, not inserted later with JavaScript.
- Host it close to users on a CDN and cache it.

```html
<!-- Example: hero with responsive sources -->
<picture>
  <source type="image/avif" srcset="/hero-640.avif 640w, /hero-960.avif 960w, /hero-1280.avif 1280w">
  <source type="image/webp" srcset="/hero-640.webp 640w, /hero-960.webp 960w, /hero-1280.webp 1280w">
  <img
    src="/hero-960.jpg"
    srcset="/hero-640.jpg 640w, /hero-960.jpg 960w, /hero-1280.jpg 1280w"
    sizes="(max-width: 640px) 100vw, (max-width: 1024px) 90vw, 1200px"
    width="1200" height="800"
    alt="Screenshot of yourproduct.com dashboard"
    fetchpriority="high"
    decoding="async"
  >
</picture>
```

> The widths, heights and quality values shown here, such as 640, 960 and 800, are typical, not measured on your site. Adjust them to your layout.

A fixed page: the hero appears sharp on the first paint on a mid-range phone, no jump, and the rest of the page starts loading after it.

> Rule: never lazy-load anything visible at first paint, especially the hero image.

## Choose the right format: AVIF, WebP or JPEG

Pick the smallest format that keeps the quality you need. Test on your own assets, not on a stock sample. Different images compress differently.

| Use when | Pros | Cons | Notes |
| --- | --- | --- | --- |
| AVIF | Photographic images, gradients, UI shots | Smallest files at a given quality, supports HDR-ish cases in some browsers | Slower to encode, older browsers may not support | Serve with <picture> and fall back to WebP or JPEG. |
| WebP | Broad default for photos and UI | Great compression, near-universal support as of 2026 | Slightly larger than AVIF on many photos | Good fallback under AVIF. |
| JPEG | Complex photos at large sizes | Fast to encode, widely supported | Bigger files, artefacts on flat colours and text | Still wins on some detailed photos after tuning. |
| PNG | Logos, icons with sharp edges, transparency | Crisp edges, lossless | Large on photos | Prefer SVG for simple shapes and logos. |
| SVG | Logos, icons, simple illustrations | Tiny, scales perfectly | Not for photos | Inline small SVG to avoid extra requests. |

- For a product screenshot on /pricing, AVIF often gives the best size without blur.
- For a lifestyle photo on /about, compare AVIF, WebP and a high-quality JPEG. Keep the smallest that looks right.
- Use PNG only when you need alpha transparency and sharp edges. Otherwise avoid it for photos.
- SVG is best for logos and simple icons. Do not convert photos to SVG.

```bash
# Examples with commonly used encoders
# AVIF (libaom or libavif via canvas or Squoosh elsewhere)
# cwebp for WebP, mozjpeg for tuned JPEG

# WebP
cwebp -q 75 input.jpg -o output.webp

# MozJPEG
mozjpeg -quality 77 -optimized -progressive input.jpg > output.jpg

# AVIF (avifenc)
avifenc --min 20 --max 28 --cq-level 28 --jobs 4 input.png output.avif
```

> Quality numbers like 75 and 77, and quantiser ranges like 20 to 28, are typical, not measured. Tune on your assets with visual checks and byte sizes.

A fixed page: /guides/getting-started serves an AVIF hero with WebP and JPEG fallbacks, and the file size halves against the old JPEG-only version.

## Responsive images that match your layout

Send only the pixels the device needs. That means a proper srcset and a realistic sizes. Do not trust a default that does not match your CSS grid.

```html
<!-- Card images in a 3-column grid above a wide breakpoint, 2-column at medium, single column on small screens -->
<img
  src="/cards/feature-640.jpg"
  srcset="/cards/feature-320.jpg 320w, /cards/feature-480.jpg 480w, /cards/feature-640.jpg 640w, /cards/feature-960.jpg 960w"
  sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw"
  width="640" height="400"
  alt="Feature card"
  loading="lazy"
  decoding="async"
>

```

> The widths and heights in this example, such as 320, 480, 640, 960 and 400, are typical, not measured on your site. Match them to your CSS layout.

- Use width and height on every img. The browser can calculate the aspect ratio and reserve space, which prevents layout shift.
- Keep the largest intrinsic width near the largest display size you actually use. Do not ship 4000 px images to a 1200 px layout.
- Use decoding=async so decoding does not block rendering.
- Prefer object-fit: cover with real image crops instead of oversized images centred in a box.

A fixed page: the cards in a grid load the 320 px files on mobile and never trigger a Cumulative Layout Shift when the images appear.

## Lazy-load and defer everything below the fold

Load images late when they are not needed for the first paint. Browsers handle native lazy loading well and start fetching before the image scrolls into view.

- Add loading=lazy on non-critical img and iframe elements.
- Use an IntersectionObserver only when you need a custom threshold or effect. Avoid scroll event handlers.
- Avoid huge placeholders. A simple background colour or a tiny blurred placeholder is enough.
- Do not lazy-load icons or logos in the header. Inline critical SVG instead.
- If a product gallery is below the fold on /product/widget, lazy-load its images and prefetch on user intent, for example on a hover or touchstart.

Google can index lazy-loaded content as long as it appears without a user action. IntersectionObserver is fine. A scroll-triggered fetch tied to an event is not.

A fixed page: the LCP hero is eager, the rest of the images have loading=lazy, and the network waterfall shows the first screen paints fast while other images queue.

## Stop layout shift: reserve space and control aspect ratios

Layout shift wrecks perceived speed and your scores. It is often images without dimensions. Always give the browser enough information to lay out the page before images arrive.

- Set width and height on every img. Modern browsers compute aspect-ratio from them.
- For CSS background images, set a container with a fixed height or an aspect-ratio.
- When an image slot can change height, reserve a min-height so later content does not jump.
- Avoid text wrapping changes by defining consistent image sizes across breakpoints.

As of 2026, a good Cumulative Layout Shift is up to 0.1. Images, videos and iframes without dimensions are a common cause. Width and height fix most of these cases.

A fixed page: /blog/how-we-built-x sets width and height on the lead image and gallery, so the text below stays put while images stream in.

## Background images and overlays without hurting LCP

Avoid CSS backgrounds for the hero. The browser discovers them later. If you must use one for an effect, help the browser find it early and size it correctly.

1. **Preload the file** <link rel="preload" as="image" href="/hero-1280.avif" imagesrcset="/hero-960.avif 960w, /hero-1280.avif 1280w" imagesizes="100vw">
2. **Give the box dimensions** Use aspect-ratio or a fixed height so the layout is stable before the image arrives.
3. **Avoid heavy overlays in the image** Prefer a CSS gradient layer or a semi-transparent overlay element rather than baking weight into the asset.
4. **Consider switching to an <img>** Use object-fit: cover on an img. You get srcset, sizes, and fetchpriority=high.

> The example widths in the preload snippet, such as 960 and 1280, are typical, not measured. Align them with the largest on-screen size of the hero.

A fixed page: the hero remains a real img with srcset and a gradient overlay in CSS, so LCP is discoverable and fetched at high priority.

## Delivery: CDNs, caching and connection hints

Fast bytes beat clever compression when your origin is slow or far. Ship images from a CDN and let the edge cache do its job. Keep connections warm for early assets.

- Serve images over HTTP/2 or HTTP/3. A CDN handles this for you.
- Set long cache lifetimes on versioned image URLs. Change the filename on updates.
- Use preconnect to image origins that must load during the first paint.
- Compress over the wire with Brotli for SVG. JPEG, WebP and AVIF are already compressed.
- Avoid redirect chains on image URLs. Link to the final URL.

```html
<!-- Connection hints in the head for an image CDN domain -->
<link rel="preconnect" href="https://img.yourcdn.com" crossorigin>
<!-- If the hero image is on a different host, preconnect helps the handshake start sooner -->
```

An image CDN that transforms on the fly is useful when you have many sizes. It should output AVIF or WebP, set width and height, and cache at the edge. Test the output quality and cache headers before you switch.

## What a framework image component does for you

Modern frameworks ship image components. They solve hard defaults so you do not repeat them on every page. Use them when they match your stack.

- Generate srcset and sizes from a single source file.
- Convert to AVIF or WebP with fallbacks when supported by your build pipeline.
- Add width and height to prevent layout shift.
- Lazy-load below the fold by default and expose a priority flag for the LCP image.
- Offer a blur-up or colour placeholder that weighs almost nothing.
- Route image requests through a CDN or an optimiser service.

Check what it emits. View source on / and /pricing. Confirm the hero has no loading=lazy, has fetchpriority=high, and that width and height are present. If not, adjust the props or override with your own markup.

## Measure the effect where it matters

Use PageSpeed Insights to see what real users get and what a single lab run says. Fix images, ship, then check again after a few days.

- The top field section reads the Chrome User Experience Report and shows a pass or fail on the Core Web Vitals assessment.
- The lower lab section is a Lighthouse run on a simulated mid-range phone on throttled 4G. Scores vary between runs.
- The LCP readout in field data is the one that matters for Search. The lab LCP helps you debug changes now.
- Total Blocking Time in lab is a proxy for interaction issues. It can delay when your hero script runs and, in turn, when images get discovered.

Largest Contentful Paint is considered good up to 2.5 seconds. Interaction to Next Paint replaced First Input Delay in March 2024. If your field data has too little traffic per URL, PageSpeed Insights falls back to origin-level data or shows none. Give your changes a few days to show in the 28-day window.

A fixed page: after moving the hero to AVIF with fetchpriority=high and adding width and height everywhere, the field LCP on Mobile improves on / from red to green over the next week.

## A checklist per image

- Is this image visible at first paint? If yes, no lazy-loading and add fetchpriority=high.
- Is the format right? Try AVIF first, then WebP, then tuned JPEG for complex photos.
- Does the markup include an accurate srcset and sizes that match CSS?
- Are width and height set so no layout shift occurs?
- Is decoding=async set, and is loading=lazy used only below the fold?
- Is the file sized to the largest display size it will have, not larger?
- Is the asset on a CDN with long cache and a versioned URL?
- For CSS backgrounds, is there a preload and a fixed height or aspect ratio?
- For framework components, did you check the emitted HTML on real pages?
- For galleries, are thumbnails light and deferred, with larger images loaded on interaction?

Work one template at a time: /, /pricing, /product/widget, then /blog/*. Measure before and after for each template, not the whole site at once.

## Questions

### How do I optimise images for PageSpeed quickly?

Fix the hero image first: AVIF or WebP, real srcset and sizes, fetchpriority=high, width and height, and no lazy-loading. Then add loading=lazy to everything below the fold, set decoding=async, and push images to a CDN with long cache. Measure on PageSpeed Insights, ship, then recheck after a few days.

### Is JPG or PNG better for the web?

For photos, use AVIF or WebP first, then a tuned JPEG if those are not available or look worse. PNG is for sharp-edged graphics and transparency. For logos and simple icons, use SVG instead of either.

### AVIF vs WebP: which should I choose?

Try AVIF first, it often gives the smallest files at a given quality. Fall back to WebP for broader support, then JPEG if needed. Test on your own assets, as some detailed photos still look better per byte with a tuned JPEG.

### What is an LCP image and how do I improve it?

LCP is the largest image, video poster, background image or text block in the initial viewport. Improve it by not lazy-loading it, adding fetchpriority=high, serving a compressed format with a responsive srcset, preloading if it is a CSS background, and hosting it on a CDN close to users. Make sure the element is present in server-rendered HTML.

### Do I need a placeholder or blur-up?

It can smooth perception for below-the-fold images, but it is optional. If you use one, keep it tiny and avoid heavy base64 strings inline that bloat HTML. The hero should load fast enough not to need a blur at all.

### Should I convert all images to one format?

No. Choose by asset type. Use AVIF or WebP for most photos and UI shots, SVG for logos and icons, and PNG only when you need sharp edges with transparency. Keep a JPEG fallback where older clients need it.

## Read next

- [Largest Contentful Paint: what slows it and what fixes it](https://porteur.ai/guides/largest-contentful-paint): See what usually counts as LCP, what makes it slow, how to fix it in order, and how to read it in Lighthouse and field data.
- [Lazy loading images: what to lazy-load and what never to](https://porteur.ai/guides/lazy-loading-images): Lazy loading images saves bandwidth. Here is what to lazy-load, what never to, how to handle iframes and backgrounds, and how it affects LCP and SEO.
- [How to read PageSpeed Insights: field data first, then the score](https://porteur.ai/guides/how-to-read-pagespeed-insights): Start with field data, not the score. Learn what Google uses, why scores vary, and how to turn a PageSpeed Insights run into a clear order of fixes.
- [Core Web Vitals for a product site: the three numbers](https://porteur.ai/guides/core-web-vitals): The product founder’s guide to LCP, CLS and INP: what Google measures, why phones decide the pass, common causes, and how to test and fix.
- [Web fonts and page speed: load one face, and load it first](https://porteur.ai/guides/web-fonts-and-page-speed): Ship crisp type without slowing first paint or shifting layout. Choose one fast path, preload the face above the fold, and stop the swap from moving text.
- [Render-blocking resources: what blocks the first paint and how to unblock it](https://porteur.ai/guides/render-blocking-resources): Stop CSS and synchronous scripts from blocking first paint. Read the Lighthouse audit and fix in order: defer, inline critical CSS, split CSS, and handle fonts.
- [On-page SEO](https://porteur.ai/glossary/on-page-seo): On-page SEO is everything on the page itself that search engines read. See what to check, how to measure it, the four rules, and the common traps.
- [Image SEO](https://porteur.ai/glossary/image-seo): A checklist for SEO on images: names, alt text, size, format, speed, and how to see if Google Images sends you traffic.

Drop your homepage URL and get a free check: in about thirty seconds it reads your site and rivals on your searches, and shows three image fixes to ship first. Free check: https://porteur.ai/
