Boost Web Performance: Mastering Image Optimization with WebP and Lazy Loading

This guide explores systematic image optimization for web applications, covering formats like WebP, lossless vs lossy compression, lazy loading, placeholder strategies, format fallback, monitoring, and practical code implementations to reduce image size, memory usage, and improve loading speed and user experience.

ELab Team
ELab Team
ELab Team
Boost Web Performance: Mastering Image Optimization with WebP and Lazy Loading

Background

During recent performance observations, it was found that images occupy a large proportion of page weight, causing blank flashes and loading delays on several pages.

Typical image‑heavy pages suffer from high first‑screen load time; Lighthouse analysis shows large image size and weight.

Optimizing these images can bring clear benefits to users and the company, but a systematic process is missing.

Before Starting

First review basic concepts such as image formats and lossless vs lossy compression.

Image Formats Overview

jpg/jpeg

png

gif

WebP

Avif

Jpeg XL

Lossy vs Lossless Compression

Lossy Compression

Lossy compression reduces data size by discarding less important information, resulting in files that are smaller on disk and in memory but differ slightly from the original.

For web image loading, lossy compression is preferred to minimize memory usage and speed up decoding.

Lossless Compression

Lossless compression reduces file size without losing any information, allowing exact reconstruction after decompression. It is used in ZIP, gzip, etc., but does not reduce memory usage after decoding.

Therefore, to reduce memory consumption, lossy compression must be used.

WebP Overview

Concept

WebP is a modern image format offering both lossless and lossy compression. Compared with PNG, lossless WebP is 26% smaller; at equal SSIM quality, lossy WebP is 25‑34% smaller than comparable JPEG. Lossless WebP supports transparency with only 22% extra bytes, and lossy WebP can also support transparency, often three times smaller than PNG.

Examples show WebP’s advantages in real‑world sites such as YouTube and Douyin PC.

Optimization Ideas

Image optimization can be divided into loading stage and display stage.

Loading Stage

Image Size

Reducing image file size directly shortens network transfer time, improving first‑contentful‑paint and related metrics.

Memory Usage

Even if file size is reduced, memory usage may remain high; optimizing memory consumption speeds up decoding and rasterization, reducing page jank.

Display Stage

Placeholder Images

Placeholders give users a perceived loading progress, reducing abandonment.

Lazy Loading

Lazy loading defers unnecessary resource requests, saving bandwidth and memory.

Format Fallback

Because browser support for image formats varies, a fallback strategy (e.g., WebP → PNG) ensures compatibility while maximizing performance.

Error Placeholder

Provide a fallback visual when all loading attempts fail.

Practice – Experiment Stage

Image Compression

Use the existing platform to generate multiple formats (original, WebP, Avif) with a chosen compression ratio (e.g., 75%). The image list includes backup URLs for fallback.

type ImgUrlList = {
  // original
  origin: string,
  // WebP format
  webp: string,
  // AVIF format
  avif: string,
}

The multi‑URL approach enables automatic fallback when a format is unsupported.

Browser statistics show Chrome 78.66% (min version 55) and Firefox min version 99, both supporting WebP; IE usage is negligible, so fallback to PNG is mainly for IE.

Image Loading

Implement the display‑stage flow using a custom image observer library that provides error retry and format fallback.

import type ImageObserver from 'xxxxxxxxx';
let imgObserver: ImageObserver;
export async function getImgObserver(): Promise<ImageObserver> {
  if (imgObserver) return imgObserver;
  const [ImageObserverSDK, LoggerSDK] = await Promise.all([
    import('xxxxxxxxx'),
    import('xxxxxxxxx-logger')
  ]);
  const ImageObserver = ImageObserverSDK?.default;
  const Logger = LoggerSDK?.default;
  if (ImageObserver && Logger) {
    imgObserver = new ImageObserver({
      plugins: [Logger],
      divider: { dataSrc: 'src', backUpSrc: 'backup-src' },
      logger: { user_unique_id: 'cccccc', app_id: 111111 }
    });
  }
  return imgObserver;
}

Lazy loading is handled manually via IntersectionObserver:

const observerCb: IntersectionObserverCallback = useCallback((entries, observer) => {
  const entry = entries[0];
  if (entry.isIntersecting) {
    setImgVisible(true);
    observer.disconnect();
  }
}, []);
const { updateObserverEl } = useIntersectionObserver({ cb: observerCb });

Loading Data Reporting

Use a logger plugin to report attempts, retries, results, and timings, enabling analysis of format success rates and fallback behavior.

Optimization Feedback

Based on collected data, decide whether to experiment with newer formats (e.g., AVIF) or adjust CDN settings, and verify that fallback strategies work as expected.

Practice – Stable Stage

After validation, remove the heavy monitoring code and rely on native browser handling, while still supporting format fallback via the picture element.

const pictureRender = () => {
  const { webp, avif, image } = remain.urlList;
  return (
    <picture>
      <source srcSet={avif} type="image/avif" />
      <source srcSet={webp} type="image/webp" />
      <img src={image} onError={() => onError?.()} {...remain} />
    </picture>
  );
};

The picture tag automatically selects the best supported format and falls back gracefully.

References

Links to articles on WebP, image compression, and responsive images are provided for further reading.

image-optimizationwebpLazy LoadingCompressionfrontend performanceResponsive Images
ELab Team
Written by

ELab Team

Sharing fresh technical insights

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.