Web Development
Image delivery: the optimisation most agencies skip
Quick answer: modern image delivery means serving the right format (AVIF, then WebP, with JPEG fallback), the right size for the device (responsive srcset and sizes), with explicit dimensions to prevent layout shift, lazy-loaded below-the-fold, and high-priority for the LCP image. Most sites do none of this. Implementing the full pipeline typically cuts image weight by 50–80% and meaningfully improves LCP.
Of all the levers available to make a website faster, image optimisation is the largest and the most consistently neglected. We audit sites every month where the hero image alone is 4–6 MB. The fix isn’t exotic; it’s well-understood and well-tooled. Agencies just don’t implement it.
This is the full picture of what image delivery should look like in 2026.
Why image delivery matters disproportionately
For a typical marketing page:
- Total page weight: 1–5 MB
- Image weight: 60–85% of total
- LCP element: usually the hero image
- Mobile loading time: largely determined by image weight
If you halve the image weight, you typically halve the LCP on mobile. No other single change has comparable impact.
Layer 1: choosing the right format
The format hierarchy in 2026:
1. AVIF. The current best. 30–50% smaller than WebP at equivalent quality. Supported in all major modern browsers (Chrome, Firefox, Safari 16+, Edge). The format to default to.
2. WebP. Still useful as a fallback. About 25–35% smaller than JPEG at equivalent quality. Supported everywhere except very old browsers.
3. JPEG. The fallback. Only relevant for browsers that support neither AVIF nor WebP — effectively a single-digit percentage of traffic in 2026.
4. PNG. Use only for images requiring transparency or sharp non-photographic graphics where AVIF/WebP show artefacts. For everything photographic, modern formats win.
5. SVG. For logos, icons, and vector graphics. Smallest possible for what it does, scales perfectly. Should be used wherever the source is vector.
The implementation pattern: serve AVIF if the browser accepts it, fall back to WebP, fall back to JPEG. Modern frameworks and image hosts handle this automatically through the <picture> element or content negotiation.
<picture>
<source type="image/avif" srcset="hero.avif">
<source type="image/webp" srcset="hero.webp">
<img src="hero.jpg" alt="..." width="1600" height="900">
</picture>
Layer 2: responsive images (srcset and sizes)
A 1600px wide image is overkill on a 400px wide phone. Serving the same file to every device wastes bandwidth and slows everything down.
The pattern: serve different image sizes based on the device’s actual viewport, using the srcset and sizes attributes:
<img
srcset="hero-400.avif 400w,
hero-800.avif 800w,
hero-1200.avif 1200w,
hero-1600.avif 1600w"
sizes="(min-width: 1024px) 1200px, 100vw"
src="hero-800.avif"
alt="..."
width="1600"
height="900"
>
What this does: tells the browser “here are four versions at different widths; pick the smallest one that’s appropriate for this layout.” Mobile devices download the 400w version; desktops download the 1200w version. Each saves substantial bandwidth.
Most modern frameworks generate this automatically. Astro’s Image component, Next.js’s next/image, and similar tools handle the entire pipeline — multiple formats, multiple sizes, srcset generation — from a single source image.
Layer 3: explicit dimensions
Every <img> tag should have explicit width and height attributes, even when the actual displayed size is responsive.
Why: without dimensions, the browser doesn’t know how much space to reserve. When the image loads, content shifts. That’s CLS — one of the three Core Web Vitals.
The width and height should match the source image’s aspect ratio. CSS sizes the actual displayed image; the attributes give the browser the aspect ratio to reserve correct space.
This is one of the easiest wins available and one of the most commonly skipped. Almost every WordPress audit we run shows missing dimensions on most images.
Layer 4: lazy loading below the fold
Images below the fold shouldn’t load until the user scrolls near them. The browser handles this with the native loading="lazy" attribute:
<img loading="lazy" src="..." width="..." height="..." alt="...">
This isn’t complicated; it just isn’t applied consistently. The pattern:
- LCP image:
loading="eager"(the default) andfetchpriority="high" - Below-the-fold images:
loading="lazy" - Images in long-form content:
loading="lazy"
Lazy loading saves substantial bandwidth on pages with many images, particularly on mobile where users may not scroll the full page. The browser native implementation is well-supported and reliable in 2026.
Layer 5: high priority for the LCP image
The LCP image deserves special treatment:
<img src="hero.avif" fetchpriority="high" loading="eager" ...>
fetchpriority="high" tells the browser to prioritise this request over other competing resources. On a typical page, this means the hero image fetches before less-important assets like analytics scripts, social embeds, and below-the-fold images.
For especially critical LCP images, also preload them in the <head>:
<link rel="preload" as="image" href="hero.avif" fetchpriority="high">
This combination of preload + high fetch priority typically shaves 200–500ms off LCP on slow connections.
Layer 6: CDN-delivered with edge caching
Images should be served from a CDN with global edge caching. This isn’t about the framework — it’s about the host.
What good looks like: images delivered from edge nodes geographically close to the user, cached aggressively (one year + immutable URLs is standard), served over HTTP/2 or HTTP/3.
Services that handle this end-to-end: Cloudflare Images, Imgix, Cloudinary, Fastly, or framework-native solutions (Vercel Image Optimization, Netlify Image CDN). DIY is possible but rarely worth it for the cost of these services on most sites.
Layer 7: art direction (advanced)
For genuinely different layouts on different devices, art direction lets you serve different crops or compositions, not just different sizes:
<picture>
<source media="(min-width: 1024px)" srcset="hero-wide.avif">
<source media="(min-width: 600px)" srcset="hero-tablet.avif">
<img src="hero-mobile.avif" alt="...">
</picture>
Use case: a hero photo where the desktop version shows a wide landscape with text on the left, but the mobile version needs a portrait crop with different text positioning. Different files entirely, served conditionally.
Not always necessary, but the right tool when you need it.
What this pipeline costs
For a serious build:
- Setup: typically 2–6 hours of one-off engineering to integrate a proper image pipeline if the framework doesn’t do it natively. Modern frameworks (Astro, Next.js, Nuxt) come with this baked in — the cost is often zero.
- Per-image cost: zero with build-time generation; pennies with on-demand image services.
- Hosting cost: typically $0–$20/month for small sites; $50–$300/month for high-traffic sites using dedicated image services.
Compared to the LCP and CWV improvement: the ROI is among the highest of any front-end optimisation.
Why agencies skip this
The honest reasons we see:
- The framework didn’t do it by default, and adding it manually is annoying. Solution: pick frameworks that do it by default.
- The CMS didn’t support it. Some CMSes (WordPress without specific plugins, for instance) don’t generate the pipeline automatically. Solution: install the plugin (Squoosh, ShortPixel, etc.) or use a different CMS for sites where performance matters.
- The team didn’t know. This is the most common. Solution: education plus tooling that makes the right way the default way.
- The original images don’t exist at multiple resolutions. Solution: build-time generation from a single high-res source.
Common questions
What’s the best image format for the web? AVIF, then WebP, with JPEG fallback. AVIF is 30–50% smaller than WebP at equivalent quality and supported in all major modern browsers in 2026. WebP is the safety net for older browsers. JPEG is the fallback for very old browsers (a small minority of traffic).
Why are responsive images important?
Mobile devices don’t need desktop-sized images. Serving 1600px images to 400px screens wastes bandwidth and slows loading. Responsive images (srcset + sizes) let the browser pick an appropriate size for each device, often saving 50–80% on mobile bandwidth.
Should I lazy-load my images?
Below-the-fold images: yes, with native loading="lazy". The LCP image: no, loading="eager" (the default). Lazy-loading the LCP image makes it slower; lazy-loading below-the-fold images makes the page lighter. Both matter.
What size should images be? Provide multiple sizes (responsive images). For a typical marketing page, common widths are 400, 800, 1200, and 1600 pixels. The browser picks based on the device. Source images should be at least 2× the largest displayed size to handle high-DPI screens cleanly.
Why does my site feel slow even though I have a CDN? A CDN solves geographic latency but doesn’t solve image weight, format, or loading priority. Sites can be on excellent CDNs and still feel slow because the images themselves are too large or loaded inefficiently. The CDN is necessary infrastructure; the rest of the pipeline is what makes a site fast.
If your images are larger than they should be and you don’t know what to do about it, start a project and we’ll audit the pipeline. The fix is usually one well-spent week.
More reading
What AI actually costs to run in production
AI demos are cheap. Production is not. Where the money actually goes when you ship an AI feature, and how to size the engineering investment around the model.
IntegrationsWhy integrations break in production (and what to design for)
Every integration that "just calls an API" eventually breaks. The five places they fail first, and the design patterns that keep them running unattended.
StrategyThe hidden costs of SaaS once your business is established
The per-seat licence is the visible cost. Integration tax, lock-in, configuration drift, and the seat tax at scale are the SaaS costs no one quotes up front.