In almost all the sites we audit, images represent the largest downloaded weight, far ahead of JavaScript and stylesheets. The HTTP Archive's Web Almanac, which analyzes millions of real pages each year, confirms this observation on a web scale: images remain the heaviest resource on a median page. And it's not just a matter of weight: in most cases, the largest element displayed on the screen, the one measured by LCP, is precisely an image.
The good news is that image optimization is one of the most profitable areas of web performance: the gains are massive, measurable, and the techniques are now standardized in browsers, without relying on third-party libraries. The less good news is that each lever has its pitfalls, and poorly applied optimization can degrade what it claims to improve. A classic example: lazy loading applied to the wrong image can cost several hundred milliseconds of LCP.
In this article, we review the entire chain: format selection, responsive sizing, loading prioritization, lazy loading, layout stability, the specific case of SVGs, hosting, and automation. As with web fonts, the goal is to give you a complete and prioritized view of optimization levers, the kind we apply in our web performance audits.
Why images are the primary performance lever
Before diving into the techniques, let's precisely position the impact. Images affect, directly or indirectly, the three Core Web Vitals metrics that Google uses to evaluate the loading experience, and on which our article what is web performance and how is it measured lays the foundation.
LCP: when the image dictates perceived speed
LCP (Largest Contentful Paint) measures the rendering time of the largest visible element in the initial viewport, with a threshold of 2.5 seconds to respect according to web.dev. However, this largest element is, in the majority of cases measured across the web, an image: a homepage banner, a product photo, an article visual.
Every link in the chain counts: the discovery of the image in the HTML, its network priority, its weight, and then its decoding. An LCP image that is too heavy, discovered late, or loaded with low priority can, on its own, cause the page to exceed the 2.5-second threshold. The format, size, and prioritization levers detailed below each address a specific link in this chain.
CLS: when the image causes layout shifts
CLS (Cumulative Layout Shift) quantifies unexpected layout shifts during loading, with a threshold of 0.1 defined on web.dev. An image delivered without known proportions forces the browser to reorganize the page upon its arrival: the paragraph the visitor was starting to read moves down one screen, their finger lands next to the intended button. On the web, images without dimensions are the primary cause of CLS, and it's a completely avoidable problem, as we'll see with explicit dimension attributes.
INP: when decoding blocks interactivity
INP (Interaction to Next Paint) assesses the page's responsiveness to clicks, typing, and taps, with a threshold of 200 milliseconds documented on web.dev. The link with images is more indirect, but very real: decoding a multi-megapixel image consumes CPU time, and on an entry-level mobile, this decoding can delay the response to an interaction if it occurs at the wrong time. Properly sized and deferred images free up the main thread when it's most needed.
Beyond the Core Web Vitals
There's also a pure bandwidth issue. An e-commerce product page commonly embeds 1.5 to 3 MB of images. On an average mobile connection, this is several seconds of download, data charged to the user, and energy consumed unnecessarily when three-quarters of these images will never be seen. Image optimization is thus the rare convergence point between performance, SEO, user experience, and efficiency.
The rest of this article follows the logical order of well-executed optimization: first reduce what is transferred (format, size), then order what is loaded (prioritization, lazy loading), and finally stabilize what is displayed (dimensions, layout).
Choosing the right format: AVIF, WebP, JPEG
The format influences the transferred weight, the CPU decoding cost, and the perceived quality. For raster images (photos, complex visuals), three formats currently cover most relevant use cases.
AVIF, the best quality-to-weight ratio
Derived from the AV1 video codec, AVIF offers the best compromise today: at equivalent visual quality, we commonly observe a gain of around 50% compared to JPEG and 20% compared to WebP. Its support is now universal on modern browsers, as confirmed by caniuse.com: Chrome since version 85, Firefox since 93, Safari since 16.4. AVIF supports transparency and wide color gamuts (HDR), making it a replacement for PNG in most cases. Its only drawback is a slightly more CPU-intensive decoding, which should be monitored on very long mobile galleries.
WebP, the modern fallback
WebP has been supported everywhere since 2020 (including Safari 14) and remains an excellent fallback format. However, be aware of a common misconception: WebP is not systematically lighter than JPEG. For an already well-compressed image, or one with low visual complexity, conversion can produce a heavier file. A serious conversion process always compares the result to the original file and keeps the lighter of the two, as recommended by web.dev.
JPEG and PNG, still useful as a last resort
JPEG retains two roles: serving as a universal fallback solution in a <picture> element, and remaining the reference format for certain images where it performs equally to WebP. PNG is now only justified for very specific cases of lossless transparency when compatibility with older environments is required. As for TIFF and BMP, they have no reason to appear in production.
In practice, format fallbacks are declared with the <picture> element: the browser iterates through the sources in order and selects the first one whose MIME type it supports, as documented on MDN.
<picture>
<source srcset="visuel.avif" type="image/avif">
<source srcset="visuel.webp" type="image/webp">
<img src="visuel.jpg" width="1200" height="800" alt="Description du visuel">
</picture>
The case of animated GIFs
Animated GIF is probably the most costly format still in circulation: a palette limited to 256 colors, no efficient inter-frame compression, and files that easily reach several megabytes for a few seconds of animation. Converting to a silent MP4 or WebM video, played in a loop, typically reduces file size by over 90% according to web.dev, for a strictly identical on-screen rendering.
Serving the right size: srcset and sizes
Changing format saves 30 to 50%. Serving an image sized for the visitor's screen can save much more: sending an image 1600 pixels wide into a space displayed at 400 pixels on mobile means transferring up to 7 times too much data. This is the most powerful lever in the entire chain, and paradoxically one of the most neglected.
The standard mechanism relies on two complementary attributes of the <img> tag, described in detail in web.dev's responsive images guide. The srcset attribute declares the available variants with their actual width in pixels. The sizes attribute tells the browser the intended display width according to the viewport. With these two pieces of information and the screen's pixel density, the browser alone chooses the most economical variant.
<img
src="hero-1200.avif"
srcset="hero-600.avif 600w,
hero-1200.avif 1200w,
hero-2000.avif 2000w"
sizes="(min-width: 1024px) 50vw, 100vw"
width="1200" height="800"
alt="Description du visuel">
Two errors consistently appear in our audits. The first: a srcset with only one variant, which is the same as not having one. You need at least two to three variants per image, excluding logos and icons. The second: a srcset with width descriptors without a sizes attribute. In this case, the browser assumes the image occupies 100% of the viewport and often downloads a variant that is too large. You also need to remember to keep the sizes values up to date: after a graphic redesign, a sizes attribute that no longer reflects the actual layout will silently cause the wrong variants to be downloaded.
The <picture> element complements this setup when the selection depends on something other than width: the format cascade seen earlier, art direction (serving a different crop on mobile), or dark mode via a prefers-color-scheme media query. The width and height dimensions are always set on the final <img> tag, never on the <source> elements.
Prioritize the important image: fetchpriority and preload
Not all images on a page are equal. There is one that deserves special treatment: the one that constitutes the LCP element, generally the large visual at the top of the page. However, by default, browsers load images at low priority until they have calculated the layout and determined which ones are visible. This delay of several hundred milliseconds directly impacts the LCP.
fetchpriority high on the LCP image
The fetchpriority="high" attribute corrects this behavior by promoting the image to a high network priority as soon as it is discovered in the HTML, as explained by web.dev. Measurements published by Addy Osmani (Chrome team) show gains of 5% to 30% on LCP depending on the stacks, with an average around 15%. For an attribute that takes one word, the effort-to-benefit ratio is unbeatable.
<img src="hero.avif"
srcset="hero-800.avif 800w, hero-1600.avif 1600w"
sizes="100vw"
width="1600" height="900"
fetchpriority="high"
alt="Visuel principal de la page">
The golden rule: only one image per page should have fetchpriority="high". If five images claim it, priority becomes meaningless and behavior reverts to default. Conversely, footer images can be assigned fetchpriority="low" to free up bandwidth for critical resources.
The CSS background-image trap
A recurring trap deserves to be highlighted: when the main visual is served as a CSS background-image, it escapes the browser's preloader, which only discovers it after downloading and parsing the stylesheet. This is one of the most frequent causes of degraded LCP that we encounter. The clean solution is to convert the element into a real <img> or <picture> tag. Failing that, a <link rel="preload" as="image"> in the <head> can trigger early download, a technique detailed in web.dev's LCP optimization guide and in our article dedicated to LCP.
<link rel="preload" as="image"
href="hero.avif"
imagesrcset="hero-800.avif 800w, hero-1600.avif 1600w"
imagesizes="100vw"
fetchpriority="high">
Is your site as fast as your visitors expect?
Defer what can wait: native lazy loading
The exact counterpart to prioritization, lazy loading consists of not downloading images located below the fold until the user gets close to them. Since 2020, this feature is native in all browsers via the loading="lazy" attribute, documented on MDN: no JavaScript, no library, no observer to write.
<img src="illustration-section-basse.avif"
loading="lazy"
width="800" height="533"
alt="Illustration de la section">
<iframe src="https://www.youtube.com/embed/xyz"
loading="lazy"
width="560" height="315"
title="Titre de la vidéo"></iframe>
The browser triggers the download when the image approaches the viewport, with an anticipation margin that depends on connection speed, as described by web.dev. The attribute also applies to iframes, which is valuable for embedded maps and video players. On this last point, we go further by recommending clickable facades, a topic related to third-party scripts.
Costly errors
The first, by far the most serious error: applying loading="lazy" to the LCP image. The browser then waits for confirmation that the image is visible before downloading it, which delays rendering by 200 to 800 milliseconds in the cases we measure. This error is all the more insidious as it is often produced by a plugin or theme that applies the attribute en masse. And the combination of loading="lazy" with fetchpriority="high" fixes nothing: lazy loading always takes precedence.
Second error: JavaScript lazy loading systems based on data-src, inherited from before 2020. They break the browser's preloader and make images invisible if the script fails, without offering any advantage over the native solution. Third error, more subtle: applying lazy loading to small, repeated images (avatars, icons), for which the mechanism's latency exceeds the benefit of deferring the download.
And async decoding?
We often encounter the decoding="async" attribute presented as an essential optimization. The reality is more nuanced: modern browsers already decode most images off the main execution thread, and the MDN documentation describes an attribute with limited scope. It is harmless and can be set by default, but its effect is only truly observable on very large images under heavy CPU pressure. In other words: to add, but certainly not a priority area for audits.
Stabilize layout: width, height, and aspect-ratio
An image without width and height attributes is an image whose proportions the browser ignores before downloading it. Consequence: it reserves zero height for it, displays the text, then redraws the entire layout when the image arrives. This visual jump is counted by the CLS, and images without dimensions have historically been the primary cause of this on the web, as the CLS optimization guide from web.dev reminds us.
Since late 2019, all browsers calculate the aspect ratio from these two attributes and reserve the exact space even before the first byte of the image. The key point, often misunderstood: HTML values do not impose the display size. CSS retains control, and the classic combination of max-width: 100% with height: auto maintains a perfectly responsive rendering while preserving the reserved ratio.
<img src="photo.avif" width="1600" height="900" alt="Description">
/* côté CSS : responsive sans casser le ratio réservé */
img {
max-width: 100%;
height: auto;
}
For CSS background images, which lack an equivalent to these attributes, the aspect-ratio property allows reserving space directly in the stylesheet. And in a <picture> element, let's recall, dimensions are declared on the final <img> tag. It's a reflex to systematize: on most sites we optimize, simply generalizing explicit dimensions is enough to bring CLS below the 0.1 threshold targeted by Google. Our guide on Core Web Vitals with WordPress details this task on the CMS side.
The special case of SVGs
For logos, icons, pictograms, and diagrams, the vector format SVG is unrivaled: it displays sharply at all resolutions, often weighs less than a kilobyte when optimized, and compresses remarkably well in Brotli or gzip since it's XML. A logo in PNG or, worse, JPEG, is an immediate red flag in an audit.
Three practices make a difference. First, systematically clean exported files from creation tools: metadata from Illustrator, Sketch, or Inkscape unnecessarily bloat the weight, and a pass through SVGO on the command line, or its web interface SVGOMG by Jake Archibald, removes them without affecting the rendering. Second, inline critical small SVGs like the header logo: this saves a network request. Finally, for icon sets, prefer a sprite declared once via <defs> and reused everywhere via <use>, rather than thirty identical SVGs repeated in the DOM.
Last point, often forgotten: an SVG without a viewBox or explicit dimensions causes the same layout shifts as a raster image without width or height. The stability rules seen above apply identically.
Host and deliver your images efficiently
The best format in the world cannot compensate for poor delivery. First principle: host images on your own domain. Each third-party domain imposes an additional DNS resolution and TLS negotiation, typically 100 to 300 milliseconds of overhead on mobile. Since Chrome partitioned its HTTP cache, the argument of a shared cache between sites has actually disappeared entirely: a third-party resource is re-downloaded for each site that uses it.
If an image CDN is justified (on-the-fly resizing, automatic format conversion based on the browser), the best practice is to serve it behind an alias CNAME of the main domain rather than from the provider's domain. We have dedicated a full article to the pros and cons of CDNs to help you decide. Second principle: an aggressive browser caching policy. Images versioned in their filename can have a Cache-Control of one year with the immutable directive, which eliminates any revalidation for subsequent visits.
Finally, the quality of the origin infrastructure remains crucial: Brotli compression enabled, HTTP/2 or HTTP/3 for parallel downloads, and controlled server response time. This is precisely what we guarantee with our WordPress hosting optimized for performance.
Automate: the production optimization pipeline
All of the above is only worthwhile if it's applied to 100% of images, including those that contributors will upload next year. Manual optimization does not scale: an automated pipeline is necessary.
On WordPress, some of the work is natively supported: the CMS automatically generates multiple sizes on upload and builds the corresponding srcset, applies loading="lazy" to images outside the initial viewport, and knows how to set fetchpriority="high" on the main image, a continuous effort by the core performance team documented on make.wordpress.org. Support for the AVIF format in the media library has been native since WordPress 6.5. Automatic conversion of uploads to AVIF can be controlled with a filter:
<?php
// Générer les tailles intermédiaires en AVIF à l'upload
add_filter( 'image_editor_output_format', function ( $formats ) {
$formats['image/jpeg'] = 'image/avif';
$formats['image/png'] = 'image/avif';
return $formats;
} );
This native foundation has its limits, however: no comparison of weight before and after conversion, global quality settings, and no handling of existing images without dedicated processing. This is where specialized plugins or a custom build pipeline come in, to be chosen based on the context. This fine-tuning, which also includes excluding the LCP image from lazy loading, is part of the standard interventions in our WordPress optimization service. Outside of the CMS, on modern JavaScript stacks, frameworks provide image components that industrialize these same principles; our SPA audits verify that they are correctly configured.
Measure before, measure after
As always in performance, we only steer what we measure. Synthetic audit tools identify most of the issues mentioned here: Lighthouse and PageSpeed Insights flag oversized images, outdated formats, images without dimensions, and candidates for lazy loading, with an estimate of the byte savings for each. We compared these two tools in a dedicated article.
The DevTools network panel complements the analysis: filter by images, sort by weight, and check the effective request priority for the LCP image. However, be careful not to conclude based solely on lab tests: only field data, from the CrUX report or a RUM tool, reflects what your visitors actually experience, on their devices and connections. This is the whole purpose of our web performance monitoring offer: to track these metrics continuously and detect regressions before they cost positions or conversions.
Key takeaways
If you were to remember only one method, it would be this one, in order. Serve modern formats, AVIF as the first choice with WebP as a fallback then JPEG, verifying that each conversion actually reduces the file size. Provide each image in multiple sizes with srcset and sizes. Give network priority to the LCP image with fetchpriority="high", and to it alone. Defer all images below the fold with loading="lazy", taking care never to apply it to the LCP image. Declare width and height on each image for stable CLS. Process SVGs with SVGO, host your images on your domain with a long cache policy, and automate everything so that the discipline survives future uploads.
Each site nevertheless has its specificities: theme, plugins, CDN, editorial habits. To know precisely where your room for improvement lies and to quantify it, a web performance audit provides a prioritized and quantified action plan; and if you prefer to delegate the entire project, our team will handle it from start to finish as part of an optimization service.