# Optimise images for the web without losing quality

[Canonical HTML page](https://gradiently.design/guide/lighthouse-image-performance)

Images are usually the heaviest part of a page and the reason Lighthouse complains. Here is a working method: the right pixel sizes, the right format, responsive markup and loading hints, without visible loss.

## The short version

- To optimize images for web, export each image at the size it is displayed, roughly doubled for high density screens, rather than uploading the original.
- AVIF and WebP produce much smaller files than JPEG and PNG at similar visual quality, and every current browser supports WebP.
- The srcset and sizes attributes let the browser download the smallest image that still looks sharp on each screen.
- Lazy load images below the fold with loading="lazy", but load the main hero image eagerly with fetchpriority="high", because it usually decides Largest Contentful Paint.
- Always set width and height on images so the browser reserves space and the layout does not jump while they load.

To **optimize images for web** without visible loss, do five things: export each image at the pixel size it is displayed (about twice that for sharp screens), choose a modern format such as AVIF or WebP, compress to a moderate quality and compare by eye, serve several sizes with `srcset`, and lazy load anything below the fold. Those steps clear most of the image warnings in Lighthouse and usually cut page weight dramatically, because the original photo straight from a camera or design tool is many times larger than the screen needs.

## Step 1: export at the size you display

An image shown 800 pixels wide does not need to be 4,000 pixels wide. Lighthouse flags oversized images because the extra pixels are downloaded, decoded and thrown away. Measure how wide the image appears in your layout at its largest, then export at roughly twice that width for high density phones and laptops. Going beyond two times rarely looks sharper and always costs bytes.

| Image | Displayed at | Export width |
| --- | --- | --- |
| Full width hero | Up to 1920 px | 1920 px, plus smaller versions |
| Article image | About 720 px | 1440 px |
| Card thumbnail | About 360 px | 720 px |
| Avatar | 48 px | 96 px |
| Open Graph image | Off site | 1200×630 exactly |

Typical targets. A full width hero is the exception to doubling: 1920 px covers most screens, and very large displays get a slightly soft image at a sensible cost.

- Website hero 1920×1080: 1920 × 1080
- Blog banner 1200×600: 1200 × 600
- Link preview 1200×630: 1200 × 630

Three common web image sizes drawn to scale. Design at the final size so nothing is cropped or scaled after export.

## Step 2: choose the right format

Format matters more than any compression slider. AVIF usually gives the smallest file, WebP comes close and is supported everywhere current, and JPEG and PNG remain the safe fallbacks. [WebP vs PNG](https://gradiently.design/guide/webp-images) and [PNG vs JPG](https://gradiently.design/guide/png-vs-jpeg) go deeper on each pair.

| Format | Best for | Notes |
| --- | --- | --- |
| AVIF | Photos, gradients, large heroes | Smallest files; slower to encode |
| WebP | Almost everything | Lossy and lossless, transparency, wide support |
| JPEG | Photos, as a fallback | No transparency; bands on smooth gradients |
| PNG | Screenshots, flat graphics, transparency | Lossless and large for photos |
| SVG | Logos, icons, illustrations | Vector, tiny when simple; see [SVG vs PNG](https://gradiently.design/guide/svg-vs-png) |

Pick by content, not habit. Smooth gradients are the hardest case for JPEG, which is where WebP and AVIF help most.

> **Gradients compress badly** Smooth colour transitions show compression as visible steps. Add a little grain before exporting, as described in [gradient banding](https://gradiently.design/guide/gradient-banding), and the encoder can work harder without anyone seeing it. Better still, draw web gradients in CSS.

A hero gradient in about 70 bytes: `linear-gradient(160deg, #0f172a 0%, #1e3a8a 50%, #0ea5e9 100%)`

This gradient, as CSS, costs less than a single line of the page. Exported as a 1920×1080 image, the same thing would weigh many kilobytes. See [CSS gradient performance](https://gradiently.design/guide/css-gradient-performance).

## Step 3: compress, then look

Lossy formats have a quality setting, and the right value depends on the image. Start around 75 to 80 for WebP and around 50 to 60 for AVIF, export, and compare against the original at 100% zoom. Lower it until you can see a difference, then step back up once. Faces, fine text and gradients need more quality than busy landscapes. [Image compression](https://gradiently.design/guide/image-compression) explains what the encoder throws away.

Strip metadata such as camera details and embedded thumbnails while you are there. Most export tools do it with one checkbox, and it removes bytes nobody sees.

## Step 4: responsive markup with srcset and sizes

With several widths exported, let the browser pick. `srcset` lists the files and their widths; `sizes` tells the browser how wide the image will appear. The browser then downloads the smallest file that is sharp enough for that screen.

```html
<picture>
  <source type="image/avif"
    srcset="/img/hero-960.avif 960w, /img/hero-1440.avif 1440w, /img/hero-1920.avif 1920w"
    sizes="100vw" />
  <source type="image/webp"
    srcset="/img/hero-960.webp 960w, /img/hero-1440.webp 1440w, /img/hero-1920.webp 1920w"
    sizes="100vw" />
  <img src="/img/hero-1920.jpg" alt="Morning light over the harbour"
    width="1920" height="1080" fetchpriority="high" decoding="async" />
</picture>
```

The browser uses the first source it supports. The img element is both the fallback and the place for alt, width, height and loading hints.

For an image inside a column, describe the layout in `sizes`, for example `sizes="(min-width: 1024px) 720px, 100vw"`. Getting `sizes` wrong is the most common reason a responsive setup still downloads the big file.

## Step 5: loading hints that matter

```html
<!-- Below the fold: let the browser wait -->
<img src="/img/team-720.webp" alt="The team at the spring workshop"
  width="720" height="480" loading="lazy" decoding="async" />

<!-- The hero: fetch first, never lazy -->
<img src="/img/hero-1920.webp" alt="Morning light over the harbour"
  width="1920" height="1080" fetchpriority="high" />
```

Width and height let the browser reserve space from the aspect ratio, so nothing shifts as images arrive. CSS can still make the image fluid with max-width: 100% and height: auto.

### Common mistakes

- `loading="lazy"` on the hero image
- No width and height, so the page jumps
- One huge file for every screen
- A JPEG of a flat logo or screenshot
- Gradient backgrounds saved as images

### Instead

- Hero loads eagerly with `fetchpriority="high"`
- Set both attributes on every img
- `srcset` with three or four widths
- SVG or PNG for flat graphics
- CSS gradients, with grain if needed

These hints map directly to Core Web Vitals. The hero image is often the Largest Contentful Paint element, which [web.dev](https://web.dev/articles/lcp) suggests should render within 2.5 seconds, and missing dimensions are a classic cause of layout shift. If your hero is a video rather than an image, the same thinking applies in [video backgrounds for websites](https://gradiently.design/guide/video-background-website).

## A checklist before you publish

1. **Measure the slot** Find the largest displayed width of each image in your layout.
2. **Export at the right sizes** One to two times the slot width, plus smaller versions for phones.
3. **Pick the format** AVIF or WebP for photos and gradients, SVG for logos, PNG only when it wins.
4. **Compress by eye** Lower quality until you see a change, then raise it a step.
5. **Mark it up** `srcset`, `sizes`, `width`, `height`, `alt`, and lazy loading below the fold.
6. **Test it** Run Lighthouse in an incognito window and check the image audits and LCP element.

Much of this is easier when the image is made at its final size in the first place. In Gradiently you design once and Pro resizes to every size in one step, then exports PNG, JPG or SVG at exact dimensions up to 4K, so the hero, the banner and the [Open Graph image](https://gradiently.design/guide/open-graph-tags) each start at the size the page will show.

## FAQ

### How do I optimize images for web without losing quality?

Export at the displayed size, use AVIF or WebP, lower the quality setting only until you can see a difference, and serve several sizes with srcset. Most visual loss comes from heavy compression, not from resizing.

### What is the best image format for websites?

WebP is the safe modern default and AVIF is usually smaller still. Use SVG for logos and icons, and keep JPEG or PNG as fallbacks.

### Should I lazy load all images?

No. Lazy load images below the fold, but load the main hero image eagerly, because delaying it slows Largest Contentful Paint.

### What size should website images be?

About twice the width they are displayed at, for sharp high density screens. A full width hero at 1920 px covers most displays.

### Why does Lighthouse say my images are not properly sized?

The file has more pixels than the space it fills on the page. Export a smaller version and use srcset and sizes so the browser picks the right one.
