Image compression for web performance

On a typical page, images account for roughly half of the bytes transferred, and the biggest one is very often the Largest Contentful Paint element that Google's Core Web Vitals measure. That makes image work the highest-leverage performance task most sites have: no framework migration, just correct sizes, a sensible quality and a little markup. This guide goes through the decisions in the order they pay off.
Why images decide your LCP
Largest Contentful Paint records when the biggest visible element finishes rendering; Google treats 2.5 seconds as the threshold for "good". On a product page, a blog post or a landing page, that element is nearly always the hero image, so its size, format and how early the browser discovers it set the score almost single-handedly. A 2 MB hero on a mobile connection can eat the whole budget before any other optimisation matters.
The fix has three parts, and compression is only one of them. The LCP image must be discoverable in the initial HTML (not injected by JavaScript or hidden behind a CSS background), it must not be lazy-loaded, and it helps to mark it with fetchpriority="high" so the browser fetches it before less important resources. Only once it is requested early does making it small pay off in full.
Dimensions first, quality second
File size scales with the number of pixels, so halving the width and height removes three quarters of the pixels before any codec gets involved. A 4000×3000 photo straight from a phone has twelve megapixels; displayed in a 800-pixel column on a 2× screen it needs 1600×1200, or 1.9 megapixels. Serving the original means sending six times the data for no visible benefit, and the browser still has to decode all twelve megapixels.
A practical rule: find the largest width at which the image is ever displayed, multiply by two for high-density screens, and cap there. Going beyond 2× is invisible on almost every device and doubles the bytes again. Batch tools make this painless: in PixelShrinkr, the "max width and height" resize applies one cap to a whole folder, and images already smaller than the cap are left at their native size.
The 75–85 quality window
JPEG and WebP quality scales are not linear. Going from 75 to 95 typically doubles or triples the file, while the visible difference at normal viewing distance is close to nil; going from 75 down to 50 saves comparatively little and introduces obvious blocking and colour banding. That is why most performance guidance, including Lighthouse's "efficiently encode images" audit, lands on 75–85 as the range where bytes and appearance balance.
Within that window, pick by content. Portraits and soft scenes look fine at 75; images with fine text, product shots with hard edges or anything the customer will zoom into deserve 85. AVIF uses a different internal scale where 50–65 often matches JPEG 80, so judge it by eye rather than by number. The most reliable method is to look: a before/after comparison slider at 100% zoom, like the one in PixelShrinkr, shows exactly where artefacts appear as you lower the slider.
srcset, sizes and picture: the right pixels for each screen
One size cannot suit a 360-pixel phone and a 1440-pixel desktop. The srcset attribute lists several versions of the same image with their widths (for example 480w, 960w, 1440w and 1920w), and the sizes attribute tells the browser how wide the image will be laid out at each breakpoint. The browser then picks the smallest candidate that covers the slot at the device's pixel density. Four or five widths, spaced roughly by a factor of 1.5, cover the real world without generating dozens of files.
The picture element adds format negotiation: list an AVIF source, then a WebP source, then the JPEG img as the fallback, and each browser takes the first type it understands. Always set width and height attributes (or a CSS aspect-ratio) on the img so the browser reserves space before the file arrives; that single habit removes most image-related Cumulative Layout Shift.
Lazy loading without hurting the fold
loading="lazy" is built into every modern browser and defers an image until it is close to the viewport, so a long article with thirty photos only downloads the first few. Use it on everything below the fold. Do not use it on the hero, on the logo, or on anything in the first screen: a lazy-loaded LCP image is discovered late, fetched late, and reliably fails the 2.5-second budget.
Pair lazy loading with reserved dimensions, otherwise images popping in as the user scrolls shift the layout under their finger. If you also add decoding="async" to below-the-fold images, the browser can decode them off the main thread instead of blocking scrolling on a large photo.
Image CDN or pre-compressed files?
Image CDNs and framework image components resize and re-encode on request, choosing AVIF or WebP from the browser's Accept header. They are convenient for user-uploaded content and for teams that will never remember to export five sizes. The costs are real, though: a paid dependency, a cold-cache penalty on the first request for each variant, and a URL scheme you do not fully control.
For a marketing site, a portfolio or a documentation site, whose images change rarely, pre-compressing at build time is simpler and faster: generate the width variants once, name files with a content hash, and serve them with a one-year immutable cache header. Batch tools do the generation in minutes; drop a folder into PixelShrinkr with a width cap and a target quality, download the ZIP, and commit the result. Both approaches can coexist: pre-compress what you author, and let a CDN handle what users upload.
The takeaway
Size images to the largest slot they fill, at most 2× for high-density screens; encode photos at quality 75–85 in WebP or AVIF with a JPEG fallback; lazy-load everything below the fold but never the hero; reserve dimensions to avoid layout shift. Pre-compress content you author, and reserve an image CDN for what users upload.
Drop your images and see how much smaller they get
More guides

JPEG vs WebP vs AVIF: which format when
Three lossy formats with different ideas about what detail to discard. Where each is supported, how fast it encodes, and when JPEG still wins.

Resizing images without visible quality loss
Resampling filters, why big reductions happen in steps, when to sharpen, what DPI means on screen, and the honest limit of upscaling.