How to Optimize Images for a Website

Optimizing images comes down to four moves: choose the format that suits the picture, export only the pixel widths the layout needs, compress each file, and control when it loads. Serve AVIF or WebP with a JPEG fallback, list widths in srcset, lazy load images below the fold, and give the hero fetchpriority high instead.

Which format for which picture
PictureBest formatFallback
PhotoAVIF or WebPJPEG
Screenshot with textWebP lossless or PNGPNG
Logo, icon, simple shapesSVGPNG
Short animationVideo (MP4 or WebM)Animated WebP

Updated

Images are usually the heaviest part of a page, and the hero is often the element measured for Largest Contentful Paint. Most of the saving comes from settings you choose once: format, widths, quality and loading behaviour. The builder below writes correct markup for those choices, and the checklist after it covers the rest.

Image markup builder

Set the file name, widths, formats and where the image sits on the page. The builder writes picture and img markup with the right loading hints.

Image optimization checklist

What to check and why
CheckHowWhy it helps
Modern formatpicture with AVIF and WebP sourcesSmaller files for the same look
Responsive widthssrcset with w descriptors plus sizesPhones skip desktop sized files
CompressionQuality tuned by eye per image typeFewer bytes per pixel
Dimensionswidth and height attributesPrevents layout shift
Lazy loadingloading="lazy" below the fold onlySaves data on long pages
Hero priorityfetchpriority="high" on the main imageFaster Largest Contentful Paint
Alt textDescribe content images; empty alt for decorationAccessibility and image search

Markup patterns to copy

AVIF and WebP with a JPEG fallback

The browser uses the first source type it supports. The img carries the size, alt text and loading hints for every format.

<picture>
  <source type="image/avif"
          srcset="/img/deck-800.avif 800w, /img/deck-1600.avif 1600w"
          sizes="(max-width: 800px) 100vw, 800px">
  <source type="image/webp"
          srcset="/img/deck-800.webp 800w, /img/deck-1600.webp 1600w"
          sizes="(max-width: 800px) 100vw, 800px">
  <img src="/img/deck-1600.jpg" width="1600" height="900"
       alt="Cedar deck with built-in bench at sunset"
       loading="lazy" decoding="async">
</picture>

Batch resize and convert with sharp

A small Node script using the sharp package: every JPEG in ./src becomes three WebP widths in ./out.

import sharp from "sharp";
import { readdir, mkdir } from "node:fs/promises";

await mkdir("out", { recursive: true });
for (const file of await readdir("src")) {
  if (!file.endsWith(".jpg")) continue;
  const stem = file.replace(/\.jpg$/, "");
  for (const width of [640, 1280, 1920]) {
    await sharp(`src/${file}`)
      .resize({ width, withoutEnlargement: true })
      .webp({ quality: 75 })
      .toFile(`out/${stem}-${width}.webp`);
  }
}

Format first

web.dev's format guide sums it up: prefer vectors when the picture is shapes and text, and use a modern raster format for photos. PNG keeps every pixel exactly, which suits screenshots but makes photos needlessly large.

The picture element lets you offer new formats without breaking old browsers. The browser takes the first source whose type it understands and falls back to the img inside.

Right size, every screen

web.dev notes that sending desktop sized images to phones can use two to four times more data than needed, and suggests three to five sizes per image. List them with width descriptors in srcset and describe the layout in sizes.

Measure the rendered width in your layout rather than guessing. A card that is a third of the screen on desktop and full width on phones needs a sizes value that says exactly that.

Loading order

Lazy loading saves bandwidth on long pages, so put loading lazy on images further down. For the main above the fold image, add fetchpriority high so it is requested before less important files.

decoding async lets the browser paint text before it finishes decoding a large picture. It is a hint, and browsers may ignore it.

How it works

  1. Decide the format from the table: photos to AVIF or WebP, flat graphics to SVG.
  2. Resize to three to five widths that cover phones through large screens.
  3. Compress each file, checking the result at full size for blur and banding.
  4. Generate the markup with the builder, marking the hero as high priority and the rest as lazy.
  5. Run a page speed test and look at the image related audits to confirm.

Tips

Frequently asked questions

WebP vs AVIF: which should I use?

Both beat JPEG for photos. AVIF is the newer format and often compresses further, while WebP encodes faster and has been supported longer. A safe pattern is a picture element offering AVIF first, then WebP, then a JPEG in the img tag for anything older.

What does the sizes attribute do?

It tells the browser how wide the image will be drawn, before layout happens, so it can pick the right file from srcset. Without sizes, a browser assumes the image fills the whole viewport and may download a much bigger file than needed.

Should every image use loading lazy?

Only images below the fold. Lazy loading waits until the browser knows where an image sits, which is a delay you do not want for anything people see straight away.

How much should I compress?

Lower the quality until you can just see a difference at full size, then step back up a notch. Busy photos hide compression well; smooth gradients, skies and text show artefacts sooner.

Do I need a plugin or service to optimize images?

No. You can resize and convert in an editor or with a free in-browser tool, then write the markup by hand. Services help when you have thousands of images or user uploads to process automatically.

Related: Image compressor, WebP converter, Website image sizes, Core Web Vitals guide, HTML images guide.

Start for free or see all free tools. We.Inc is free to start, with no card needed. AI building is on paid plans from $20 a month.

More in Guides

We.Inc is an AI-powered website builder you can resell under your own brand. Launch a branded client dashboard, bill on Stripe Connect, and deliver AI-generated websites in minutes. White-label plans start at $99 a month for 25 client sites, with a 7-day free trial and no per-site fees.

Product

Who It's For

Features

Resources

Company

View Sitemap