Image optimization — practical guide
Everything ImageLens evaluates, with the why behind each rule and side-by-side examples.
1. Serve at the real displayed size
If an image renders at 320×320 on screen but the file is 1080×1080, you are sending ~10× more pixels than needed. Mobile pays for it in battery, data and load time.
| Use on the LP | Recommended width | Target weight |
|---|---|---|
| Icon / avatar | 64–128px | ≤ 20 KB |
| Small card | 320–480px | ≤ 60 KB |
| Large card | 600–800px | ≤ 120 KB |
| Hero mobile | 600–900px | ≤ 150 KB |
| Hero desktop | 1200–1600px | ≤ 250 KB |
Want to test a specific image? Use the Optimize image tab.
2. Use WebP or AVIF instead of PNG/JPG
Modern formats compress much better with no visible quality loss.
- AVIF — best compression today (~50% smaller than JPEG). Ideal for photos.
- WebP — great balance of size and support. Recommended default.
- PNG — only for logos, icons and art with transparency.
- JPEG — photos when WebP/AVIF aren't possible.
- SVG — vector, scales without loss. Ideal for icons and logos.
You can convert with the Optimize image tab on this site, or with tools like Squoosh and TinyPNG.
3. srcset and sizes — one image per screen
With srcset you provide multiple versions of the image; the browser picks the best one for the current screen (width + pixel density).
srcset, the same heavy file goes to the iPhone SE and to the 4K monitor. You waste bandwidth on small screens.<img
src="/img/produto-640.webp"
srcset="
/img/produto-320.webp 320w,
/img/produto-640.webp 640w,
/img/produto-1080.webp 1080w"
sizes="(max-width: 768px) 80vw, 320px"
alt="..."
width="640" height="640"
loading="lazy" decoding="async"
/>The browser picks the right version per viewport and DPR.
<img
src="/img/produto-1080.png"
alt="..."
/>Same big file for everyone. No dimensions → CLS.
4. Lazy load below the fold (never on the LCP)
Use loading="lazy" on images below the first viewport. Never on the hero or LCP image.
lazy, the browser delays the download until the image is near the viewport. On the hero/LCP that postpones the largest element render — exactly what the Core Web Vital measures.<!-- Hero / LCP: prioridade alta -->
<img src="/hero.webp" alt="..."
fetchpriority="high" decoding="async" />
<!-- Abaixo da dobra: lazy -->
<img src="/depoimento.webp" alt="..."
loading="lazy" decoding="async" /><!-- Lazy no hero atrasa o LCP -->
<img src="/hero.webp" alt="..."
loading="lazy" />5. Prioritize the LCP image
LCP (Largest Contentful Paint) is the time to render the biggest visible element — almost always a hero image. It is one of Google's three Core Web Vitals.
fetchpriority="high" and <link rel="preload"> tell the browser "start downloading this before anything else". Without them, it discovers the image only after parsing the entire HTML.<!-- No <head> -->
<link rel="preload" as="image"
href="/hero-1200.webp"
imagesrcset="/hero-600.webp 600w, /hero-1200.webp 1200w"
imagesizes="100vw" />
<!-- No <body> -->
<img src="/hero-1200.webp" alt="..."
width="1200" height="800"
fetchpriority="high" decoding="async" />6. Always set width and height
Even if CSS resizes it, declare width and height with the original ratio. The browser reserves the space before the image loads.
Click "Reload" and watch the layout jump in the right card.
Text below the image stays stable.
Text below the image is pushed when it loads.
<img src="/foto.webp" alt="..."
width="640" height="360" />Reserved space → zero layout shift.
<img src="/foto.webp" alt="..." />Content below jumps when the image arrives.
7. Beware of CSS background-image
The browser discovers background-image late in the pipeline — only after downloading and parsing the CSS. For critical images (hero, LCP), prefer <img>.
<img> tags are detected by the browser's preload scanner as soon as HTML arrives. background-image waits for the CSSOM. Typical difference: 200–600ms on LCP.<!-- Hero como <img> -->
<img src="/hero.webp" alt="..."
fetchpriority="high" />Detected immediately by the preload scanner.
<!-- Hero como background -->
<div class="hero" style="background-image: url(/hero.webp)"></div>Only loads after CSS — delays LCP.
8. Final checklist
- Real size checked (at most 2× the displayed size)
- Converted to WebP or AVIF
- Responsive variants with
srcset+sizes loading="lazy"on below-the-fold imagesfetchpriority="high"+ preload on the herowidthandheightalways set- Descriptive
alt(a11y and SEO) - PageSpeed Insights re-run and LCP < 2.5s