100% Private

Web Image Optimization: Formats, Compression, and Performance

Images typically account for 50% or more of a page's total weight. That means image optimization is the single highest-leverage thing you can do for page speed on most sites — bigger impact than minifying JS, enabling HTTP/2, or any other common optimization. This guide covers how to choose formats, how compression actually works, how to serve the right size to every device, and how all of it connects to Core Web Vitals.

Format Selection: JPEG, PNG, WebP, AVIF, SVG

Picking the wrong format is the most common image optimization mistake. A PNG for a photo or a JPEG for a logo with transparency will always underperform, regardless of how aggressively you compress it.

FormatBest ForTransparencyCompressionBrowser Support
JPEGPhotos, complex imagesNoLossyUniversal
PNGGraphics, logos, screenshots with textYes (alpha)LosslessUniversal
WebPEverything (modern replacement for JPEG and PNG)Yes (alpha)Both97%+
AVIFMaximum compression, modern browsersYes (alpha)Both~90%
SVGIcons, logos, illustrations, chartsYesVector (scalable)Universal
GIFSimple animations (use WebP/video instead)1-bit onlyLosslessUniversal

JPEG

JPEG is still the right choice for photographs and photographic-quality images when you need maximum compatibility. It uses DCT-based lossy compression that's very efficient for continuous-tone images — the kind where adjacent pixels are usually similar in color. It handles noise and gradients well.

JPEG cannot do transparency. If your photo needs a transparent background, use WebP or PNG instead. JPEG also accumulates quality loss every time you re-save — always keep your original and export fresh from it rather than re-saving the compressed version.

PNG

PNG uses lossless compression, which makes it ideal for images with sharp edges, flat colors, or text. Screenshots look better as PNG than JPEG because JPEG's block-based compression creates visible artifacts around sharp transitions. PNG supports full alpha transparency (not just 1-bit like GIF), making it the go-to for UI elements and logos.

The problem with PNG for photos: a full-quality photograph as a PNG is enormous — often 10x larger than a quality-80 JPEG. Never use PNG for photos unless you specifically need lossless quality.

WebP

WebP was designed by Google to replace both JPEG and PNG. It delivers 25-35% better compression than JPEG at equivalent visual quality, and 20-26% better than PNG for lossless images. It supports alpha transparency, both lossy and lossless modes, and animated images.

Browser support is now at 97%+ — Safari added support in version 14 (2020). For most projects, you can use WebP as the primary format with a JPEG/PNG fallback for the remaining 3%, or just drop the fallback entirely if your analytics show your audience is current.

AVIF

AVIF is the newest mainstream format, derived from the AV1 video codec. It achieves 50% smaller files than WebP at similar quality — a meaningful improvement. It also handles HDR content and wide color gamuts better than older formats.

The tradeoffs: encoding is slow (10-100x slower than WebP), tooling support is still maturing, and browser support is around 90% (Chrome 85+, Firefox 93+, Safari 16.4+). The right approach is to offer AVIF with WebP and JPEG fallbacks using the <picture> element.

SVG

For anything that's essentially a drawing — logos, icons, diagrams, charts, illustrations — SVG is almost always the right choice. It scales to any resolution without quality loss and is typically smaller than a raster equivalent once gzipped. You can style SVG with CSS, animate it, and make it interactive.

SVG is not suitable for photographs or complex photorealistic images. Don't use SVG for images that started as raster — exporting a photo to SVG will embed the raster data inside an SVG wrapper, giving you the worst of both worlds.

Decision Tree

Is it a line drawing, logo, or icon?
└── YES → SVG

Is it a photograph or photo-realistic image? └── YES → WebP (lossy, quality 75-85) + JPEG fallback if broad compat needed

Does it need transparency? └── YES → WebP (with alpha) + PNG fallback

Is it a simple animation? └── YES → WebP (animated) or MP4 video (avoid GIF — poor compression)

Otherwise: └── WebP lossy → JPEG fallback

Convert images with the Image Converter tools — JPG to WebP, PNG to WebP, and more, all processed locally in your browser.

Lossy vs Lossless Compression

Lossy Compression

Permanently discards image data. The original cannot be recovered from the compressed version.

  • Typical reduction: 60-90%
  • Quality loss may be imperceptible or visible depending on settings
  • Formats: JPEG, WebP (lossy mode), AVIF (lossy mode)
  • Best for: photographs, complex scenes
Lossless Compression

Reduces file size without changing any pixel values. Decompresses to the exact original.

  • Typical reduction: 10-50%
  • No quality loss whatsoever
  • Formats: PNG, WebP (lossless mode), AVIF (lossless mode), FLAC
  • Best for: graphics with text, sharp edges, screenshots

The practical rule: use lossy for photos, lossless for everything that isn't a photo. An artifact in a photograph at quality 80 is usually invisible. The same artifact on a screenshot with text or a UI mockup looks terrible.

A common mistake is using PNG for photos out of a misguided preference for "quality." PNG lossless compression on a photo produces a file 3-5x larger than a quality-85 JPEG with no perceptible visual difference. You're paying enormous storage and bandwidth costs for no benefit.

Compression Settings and Quality

Quality settings are not standardized across tools — quality 80 in ImageMagick is different from quality 80 in Photoshop. Always do a visual comparison at your target quality setting. The numbers below are starting points, not universal truths.

JPEG Quality Guide

Quality 85-95: Hero images, portfolio, product photos
Minimal visible artifacts, large files
Use when image quality is the primary concern

Quality 75-85: Standard website images, blog photos Good balance — most people can't spot artifacts Recommended default for general use

Quality 60-75: Thumbnails, background images, decorative photos Some artifacts visible at 100% zoom Acceptable for small or non-focal images

Quality 40-60: Very low priority images, placeholders Obvious quality loss — use sparingly

WebP Quality Guide

WebP quality 80 ≈ JPEG quality 85 (roughly equivalent perceptual quality)

Quality 80-90: High quality, ~30% smaller than equivalent JPEG Quality 70-80: Good quality, recommended default Quality 50-70: Thumbnails and lower-priority images

PNG Optimization

PNG doesn't have a quality slider since it's lossless. Optimization focuses on compression level and color depth:

  • Compression level 6-9: Better compression, slower to encode. Use level 9 for files that will be served millions of times.
  • Reduce color depth: If your image uses fewer than 256 colors, convert to PNG-8 (indexed color). Saves 30-60% vs PNG-32 with no quality loss for simple graphics.
  • Strip metadata: EXIF data in PNG can add kilobytes of dead weight.
  • Use pngquant for lossy PNG: pngquant reduces PNG-32 to PNG-8 with a perceptual color matching algorithm. Often achieves 60-80% reduction with near-identical appearance for icons and UI elements.

Real Size Comparison

Here's what a typical 1200×800 photo looks like at different formats and settings:

Format / SettingFile SizeNotes
PNG (lossless)~2.1 MBNo quality loss, but huge for photos
JPEG quality 95~650 KBNear-lossless, large
JPEG quality 80~180 KBGood quality, typical for web
WebP quality 80~120 KB35% smaller than equivalent JPEG
AVIF quality 60~70 KBComparable quality to WebP 80

The jump from a raw PNG to a well-compressed WebP is a 17x file size reduction. On a page with 10 images, that's the difference between 21 MB and 1.2 MB.

Responsive Images with srcset

The point of responsive images is simple: don't send a 1600px-wide image to a phone with a 375px display. The phone would download 10x more data than it can use, and it would actually look worse due to downscaling quirks.

srcset with Width Descriptors

<img
src="photo-800.jpg"
srcset="
photo-400.jpg 400w,
photo-800.jpg 800w,
photo-1200.jpg 1200w,
photo-1600.jpg 1600w"
sizes="(max-width: 600px) 100vw,
(max-width: 1200px) 50vw,
800px"
alt="Description"
width="800"
height="533"
>

The sizes attribute tells the browser how wide the image will actually be rendered. The browser uses this, combined with the viewport width and device pixel ratio, to pick the best source from srcset. You don't control which one it picks — the browser decides based on current conditions, including network speed in some implementations.

Format Fallbacks with <picture>

<picture>
<source
type="image/avif"
srcset="photo-800.avif 800w, photo-1600.avif 1600w"
sizes="(max-width: 800px) 100vw, 800px"
>
<source
type="image/webp"
srcset="photo-800.webp 800w, photo-1600.webp 1600w"
sizes="(max-width: 800px) 100vw, 800px"
>
<img
src="photo-800.jpg"
srcset="photo-800.jpg 800w, photo-1600.jpg 1600w"
sizes="(max-width: 800px) 100vw, 800px"
alt="Description"
width="800"
height="533"
>
</picture>

The browser reads <source> elements top to bottom and uses the first one it supports. AVIF-capable browsers get AVIF, WebP-capable browsers get WebP, everything else gets JPEG.

Retina / HiDPI Displays

Retina displays have a device pixel ratio (DPR) of 2 or more — they need twice as many physical pixels to display a crisp image. If you show a 400px image on a 2x display using a 400px source, it looks blurry.

<!-- Pixel density descriptors -->
<img
src="photo-400.jpg"
srcset="photo-400.jpg 1x, photo-800.jpg 2x, photo-1200.jpg 3x"
alt="Description"
width="400"
height="267"
>

The good news: because you're serving WebP with good compression, serving 2x images is affordable. A WebP photo at 800px and quality 80 is often smaller than its JPEG equivalent at 400px.

Breakpoints to Cover

  • 320-375px: Small phones (need 320-750px image at 1x-2x)
  • 768px: Tablets (need 768-1536px image)
  • 1024-1440px: Laptops and desktops
  • 1920px+: Large monitors, 4K displays

You don't need a source for every possible width. Usually 3-4 sizes cover the range well — browsers interpolate and pick the nearest one up.

Lazy Loading

Native lazy loading is now supported in all major browsers and costs nothing to implement:

<img
src="photo.jpg"
loading="lazy"
width="800"
height="600"
decoding="async"
alt="Description"
>

The browser will not download this image until it's within a certain distance from the viewport. How far depends on connection speed and browser implementation — typically within one or two viewport heights.

Critical Rules for Lazy Loading

  • Never lazy load above-the-fold images. If an image is visible when the page first loads, lazy loading it will delay its appearance and hurt your LCP score. Use loading="eager" (the default) for hero images and anything visible on initial load.
  • Always set width and height. Without dimensions, the browser doesn't know how much space to reserve, and the page will reflow when the image loads (CLS penalty). Set the actual pixel dimensions of the image, not the CSS display size.
  • Add decoding="async". This tells the browser it can decode the image off the main thread, reducing jank.

<!-- Above the fold: load immediately, no lazy loading -->
<img
src="hero.webp"
alt="Hero image"
width="1200"
height="600"
fetchpriority="high"
>

<!-- Below the fold: lazy load --> <img src="gallery-1.webp" alt="Gallery image" width="400" height="300" loading="lazy" decoding="async" >

The fetchpriority="high" hint on the hero image tells the browser to prioritize loading it — useful when LCP is the hero image and you want the browser to fetch it as early as possible.

Core Web Vitals Impact

Google's Core Web Vitals directly measure user experience, and images affect all three main metrics.

LCP — Largest Contentful Paint

LCP measures how long until the largest visible element is rendered. On most pages, this is a hero image. An unoptimized hero image delays LCP significantly.

  • Compress the hero image aggressively (it's full-width so you can't see compression at normal zoom)
  • Use WebP or AVIF — the format savings on a large image are substantial
  • Don't lazy load the LCP image
  • Preload the LCP image: <link rel="preload" as="image" href="hero.webp">
  • Serve it from a CDN geographically close to users

Good LCP: under 2.5 seconds. Most sites fail this because of large, unoptimized hero images.

CLS — Cumulative Layout Shift

CLS measures unexpected layout jumps. The most common cause is images without dimensions — the browser doesn't know how tall the image will be, so it reserves no space. When the image loads, content shifts down.

<!-- Bad: no dimensions, causes CLS -->
<img src="photo.jpg" alt="Photo">

<!-- Good: dimensions prevent layout shift --> <img src="photo.jpg" alt="Photo" width="800" height="600">

<!-- For responsive CSS images, use aspect-ratio --> <img src="photo.jpg" alt="Photo" width="800" height="600" style="width: 100%; height: auto;" >

FID/INP — Interaction Responsiveness

Image decoding can block the main thread and make pages unresponsive. Use decoding="async" to offload decoding, and avoid very large images that take a long time to decode even after downloading.

CDN Delivery

A CDN (Content Delivery Network) caches your images on servers geographically close to users. A user in Tokyo gets the image from a server in Tokyo, not from your origin server in Virginia. This reduces latency dramatically — often 100-500ms per image request.

Image CDNs

Image CDNs go further: they transform images on-the-fly. You store one original, and the CDN serves the right format and size for each request.

// Cloudinary example: serve WebP at 800px wide, quality 80
https://res.cloudinary.com/yourcloud/image/upload/w_800,q_80,f_auto/photo.jpg

// imgix example https://yoursite.imgix.net/photo.jpg?w=800&q=80&fm=webp

// Cloudflare Images example https://imagedelivery.net/hash/photo/w=800

f_auto (Cloudinary) or auto=format (imgix) instructs the CDN to detect what the browser supports and serve AVIF, WebP, or JPEG accordingly — without you having to maintain multiple copies or use <picture>.

Self-Hosted: Generate Multiple Formats at Build Time

If you don't use an image CDN, generate all format variants at build time:

# Using Sharp (Node.js)
const sharp = require('sharp');

await sharp('original.jpg') .resize(800) .webp({ quality: 80 }) .toFile('photo-800.webp');

await sharp('original.jpg') .resize(800) .avif({ quality: 60 }) .toFile('photo-800.avif');

await sharp('original.jpg') .resize(800) .jpeg({ quality: 80, mozjpeg: true }) .toFile('photo-800.jpg');

Tools and Workflows

Online Tools

For one-off conversions and quick optimization:

  • Image Converter — Convert between formats including WebP, AVIF, JPEG, PNG
  • Image Editor — Resize, crop, compress, and edit images in-browser

Command-Line Tools

# ImageMagick — versatile, handles almost any format
convert input.jpg -resize 1200x -quality 80 -strip output.jpg

-strip removes EXIF data

cwebp — Google's WebP encoder

cwebp -q 80 input.png -o output.webp

Sharp CLI — fast, Node.js based

npx sharp-cli input.jpg --resize 800 --format webp --quality 80 -o output.webp

SVGO — optimize SVG

svgo input.svg -o output.svg svgo --multipass input.svg -o output.svg # More thorough

pngquant — lossy PNG compression

pngquant --quality=65-80 --output output.png input.png

Batch convert directory with ImageMagick

mogrify -format webp -quality 80 -path ./webp/ *.jpg

Build Tool Integration

  • Vite: vite-plugin-image-optimizer — compresses on build
  • Webpack: image-minimizer-webpack-plugin with Sharp or Squoosh
  • Next.js: Built-in next/image — handles optimization, lazy loading, responsive images automatically
  • Astro: Built-in <Image /> component with similar automatic optimization
  • 11ty: @11ty/eleventy-img — generates multiple sizes and formats at build time

Batch Optimization Workflow

For a typical project with a directory of source images:

1. Start with high-quality originals (keep these)
2. Determine display dimensions (max width at any breakpoint)
3. Generate 1x and 2x sizes for each breakpoint
4. Convert each to WebP (and optionally AVIF)
5. Keep JPEG fallbacks for old browsers
6. Strip EXIF metadata
7. Update HTML to use <picture> or srcset

Before and After Examples

Product Photo (E-commerce)

VersionFile SizeWhat Changed
Camera original (RAW export)4.2 MB JPEG
Resized to 800×800px380 KB JPEGResized to display size
JPEG quality 80160 KB JPEGCompression applied
WebP quality 80105 KB WebPFormat conversion
WebP + stripped EXIF98 KB WebPMetadata removed

Result: 4.2 MB down to 98 KB — a 97.7% reduction. The product photo looks identical at normal viewing size.

Blog Header Image

VersionFile SizeNotes
Original 2400px JPEG1.8 MBDownloaded from stock photo site
Resized to 1200px290 KB JPEGMax display width on desktop
WebP quality 7585 KB WebPHeaders can tolerate lower quality

Screenshot with Text

VersionFile SizeNotes
PNG screenshot (original)280 KB PNGLossless, text is sharp
WebP lossless190 KB WebPStill lossless, text still sharp, 32% smaller
JPEG quality 8065 KB JPEGText shows JPEG artifacts — not acceptable

For screenshots, lossless compression is the right call even if it's larger. JPEG artifacts on text are clearly visible and unprofessional.

Optimization Checklist

Before Publishing Each Page

Image Tools

Privacy Notice: This site works entirely in your browser. We don't collect or store your data. Optional analytics help us improve the site. You can deny without affecting functionality.