Image loading: formats, lazy loading and fetchpriority

Pick the right file format for each image, and tell the browser which images to load first and which can wait.

  • Beginner
  • 6 min read
  • Updated 17 Oct 2026

What you will learn

  • Pick an image format for the content
  • Lazy-load images below the fold
  • Prioritise the main image with fetchpriority

Before you start

Images are usually the heaviest part of a page. Choosing the right format can make files much smaller, and a few attributes on img let you control when each image downloads, so the image people see first arrives first.

Choosing a format

FormatBest forNotes
AVIFPhotos and complex imagesUsually the smallest files at a given quality; slower to encode
WebPPhotos, and graphics that need transparencySmall files, very widely supported
JPEGPhotosUniversally supported fallback; no transparency
PNGScreenshots, graphics with sharp edges, transparencyLossless; large for photos
SVGLogos, icons, simple illustrationsVector, so sharp at any size; can be styled with CSS
GIFVery small, simple animationsLarge and limited to 256 colours; prefer video for animation

Some practical rules:

  • Photos: AVIF or WebP, with JPEG as a fallback if you need one.
  • Logos and icons: SVG.
  • Screenshots and diagrams with text: PNG or lossless WebP, or SVG if you can draw it as vectors.
  • Animations: a short muted video in MP4 or WebM, which is typically far smaller than an animated GIF.

AVIF and WebP are supported by all current major browsers. If you need a fallback for older browsers, the picture element lets the browser choose the first format it supports:

HTML
<picture>
  <source srcset="loaf.avif" type="image/avif">
  <source srcset="loaf.webp" type="image/webp">
  <img src="loaf.jpg" alt="Sourdough loaf on a wooden board" width="1200" height="800">
</picture>

The img is required. It provides the alt text, the dimensions and the final fallback. The picture element and srcset for different screen sizes are taught in depth in the Responsive Web Design course.

Compression settings matter as much as the format. Export photos at the largest size they will actually be displayed, not straight from the camera, and compare quality settings visually. Tools such as Squoosh let you compare formats side by side.

Lazy loading

By default, the browser downloads every image in the page as soon as it finds it, including images far below the visible area that the visitor may never scroll to. loading="lazy" tells the browser it can wait until the image is close to the viewport:

HTML
<img src="gallery-1.webp" alt="Croissants cooling on a rack" width="800" height="600" loading="lazy">

The attribute has two values: lazy and eager. eager is the default, meaning load straight away. Browsers start loading lazy images some distance before they scroll into view, so most people never see a gap.

Browser-level lazy loading for images is Baseline and works in all current major browsers. Browsers that do not support it ignore the attribute and load the image normally, so it is safe to use.

iframe elements support loading="lazy" too, which is useful for embedded maps and videos further down the page.

Do not lazy-load the main image

The most important image on the first screen, often a hero image or a product photo, is usually what the Largest Contentful Paint (LCP) metric measures. Lazy-loading it delays it, because the browser must first work out the layout before deciding to fetch it.

HTML
<!-- Wrong: the hero is lazy and loads late -->
<img src="hero.avif" alt="Fresh loaves on the bakery counter" width="1600" height="900" loading="lazy">

<!-- Right: the hero loads straight away -->
<img src="hero.avif" alt="Fresh loaves on the bakery counter" width="1600" height="900">

A simple rule: leave images in the first screenful eager, and lazy-load the rest. Because the visible area varies by device, err on the side of keeping the first few images eager.

Lazy loading needs width and height. Without dimensions, lazy images take up no space until they load, so content jumps as people scroll, and browsers may even load more images than necessary.

fetchpriority

Browsers give images a lower fetch priority than CSS and scripts at first, and only raise the priority of an image once layout shows it is visible. fetchpriority lets you give a hint up front:

HTML
<img src="hero.avif" alt="Fresh loaves on the bakery counter" width="1600" height="900" fetchpriority="high">
ValueMeaning
highFetch this sooner than similar resources
lowFetch this later than similar resources
autoLet the browser decide (the default)

Use fetchpriority="high" on one image: the LCP image, such as the hero or main product photo. Marking everything as high priority means nothing is. fetchpriority="low" can help with images in the first screen that matter less, such as the second and later slides of a carousel.

fetchpriority is supported in current versions of the major browsers. Browsers that do not support it ignore it, so it is a safe progressive enhancement. Check its Baseline status on web.dev if you need to know about specific versions.

decoding

After an image downloads, the browser must decode it into pixels. decoding is a hint about whether that work may happen without holding up other content:

  • async: decode off the main path, so other content can render first.
  • sync: decode together with other content.
  • auto: let the browser decide (the default).

In practice, modern browsers already make sensible choices, and the effect of decoding is usually small. It is fine to leave it out. If you use it, decoding="async" on non-critical images is the common choice.

Putting it together

HTML
<!DOCTYPE html>
<html lang="en-GB">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Our bakery</title>
  <style>img { max-width: 100%; height: auto; }</style>
</head>
<body>
  <main>
    <h1>Our bakery</h1>
    <img src="hero.avif" alt="Fresh loaves on the bakery counter" width="1600" height="900" fetchpriority="high">

    <h2>From the oven this week</h2>
    <img src="rye.webp" alt="Seeded rye loaf, sliced" width="800" height="600" loading="lazy" decoding="async">
    <img src="buns.webp" alt="Cinnamon buns with white icing" width="800" height="600" loading="lazy" decoding="async">
  </main>
</body>
</html>

Check the effect in DevTools: in the Network panel, scroll slowly and watch the lazy images request only as you approach them. The Priority column (enable it by right-clicking the column headers in Chrome) shows the hero as High.

Summary

  • Use AVIF or WebP for photos, SVG for logos and icons, PNG for sharp-edged graphics, and video instead of GIF.
  • Provide format fallbacks with picture when needed; the img inside is always required.
  • Add loading="lazy" to images below the first screen, never to the main image.
  • Add fetchpriority="high" to the single most important image.
  • Keep width and height on every image, especially lazy ones.