OMAR
Field NotesCV
Core Web Vitals on an Image-Heavy Site
← All Notes
Performance16 April 2026 · 8 min read

Core Web Vitals on an Image-Heavy Site

Photography studios, interior designers, florists — my clients sell with pictures. Making those sites fast is a constraint problem, not a plugin you install.

Most of my clients sell with pictures. A photography studio, an interior design catalog, a florist, a construction company showing finished buildings. For all of them the images are the product, so "just use fewer images" is not advice — it is asking them to sell less.

Making these sites fast is a constraint problem. Here is the order I work in, because the order matters more than any individual trick.

Fix the largest element first

Largest Contentful Paint on an image-heavy page is almost always one specific image — the hero. Everything else is noise until that one is handled.

Three things, applied together:

<link rel="preload" as="image" href="/hero.webp" fetchpriority="high">
<img src="/hero.webp" width="1600" height="900"
     fetchpriority="high" decoding="async" alt="...">

Preload it so discovery does not wait for CSS. Mark it high priority so it wins the bandwidth race against fonts and scripts. And critically — do not lazy-load it. A loading="lazy" on the hero delays the very element being measured, which is a surprisingly common own goal.

Everything below the fold gets loading="lazy". Everything.

Reserve space or pay in layout shift

An image without dimensions is a layout shift waiting to happen. The fix is to always set width and height attributes — the browser uses them to compute an aspect ratio and hold the space, even when your CSS overrides the actual size.

img { max-width: 100%; height: auto; }

For galleries where the aspect ratio is known, aspect-ratio on the container removes the last source of movement. Cumulative Layout Shift on a photography site should be effectively zero, and there is no excuse when it is not.

Serve the right bytes, not just the right format

WebP over JPEG is the easy win — typically 25 to 35 percent smaller at equivalent quality. Converting a client's screenshot folder took me minutes and removed megabytes.

The bigger win is resolution discipline. A 4000-pixel-wide photograph rendered in a 400-pixel card is 100 times the pixels needed. Generate a few widths and let the browser choose:

<img src="/shot-800.webp"
     srcset="/shot-400.webp 400w, /shot-800.webp 800w, /shot-1600.webp 1600w"
     sizes="(max-width: 640px) 100vw, 33vw"
     width="800" height="500" loading="lazy" alt="...">

Getting sizes right is worth more than another round of compression, because it changes which file is downloaded rather than shaving a few kilobytes off the wrong one.

Quality settings are not a moral question

Sixty to seventy-five is the range where I stop being able to tell in a blind comparison at normal viewing size, and it is often half the bytes of ninety. Test on the actual photographs — high-detail images tolerate less compression than soft ones — but do not default to ninety out of caution. That caution costs the visitor real seconds.

Fonts compete with your images

On a visual site, fonts and images fight for the same early bandwidth. Self-host the fonts, subset them, preload only the one or two faces used above the fold, and let the rest arrive late with font-display: swap.

Every request you remove from the critical path is bandwidth handed back to the image that is being measured.

Then measure honestly

Local testing on fast hardware lies. Run Lighthouse with mobile throttling, and pay attention to field data if you have it — real users on real networks are the only measurement that counts.

The pattern I see repeatedly: a site scores well in the lab and poorly in the field because the lab run had a warm cache and a fast connection, and the client's actual customers are on mobile data in a building with bad reception.

On an image-heavy site the goal is not fewer images. It is that the first meaningful image arrives fast and nothing moves afterwards.

The order of operations

  1. Identify the LCP element. Preload it, prioritise it, never lazy-load it.
  2. Dimensions on every image; aspect ratios on every container.
  3. Modern formats, sensible quality, and multiple widths with correct sizes.
  4. Lazy-load everything below the fold.
  5. Self-hosted, subset, preloaded fonts.
  6. Measure throttled, then measure in the field.

Six steps, no plugins, and it works on any stack — because none of it is framework-specific. It is just deciding what the browser should do first.

Core Web VitalsLCPImagesWebP

Need this built properly?

I build secure, fast, bilingual platforms for clients across Egypt, Saudi Arabia, the UAE and Kuwait.

Keep Reading