Pular para o conteúdo
~/.primo-academy.sh
☰ Aulas · Edge Deploy Frontend: build, runtime, Cloudflare Workers, Vercel Edge, image opt, preview envs, atomic deploys · 0/7
Recomendado: essencial

Image optimization: Next/Image, Cloudflare Images, formato moderno, lazy

3 min de leitura

fonte

Voce fez deploy, app rapido, mas LCP esta' acima de 4s. Investigando, a imagem hero = 3MB JPEG. Usuario em 3G demora 8s pra baixar. Esse no cobre image optimization: Next/Image, Cloudflare Images, formato moderno (WebP, AVIF), e lazy loading pra LCP < 2.5s.

Imagens sao 50%+ do peso total de uma pagina web media. Otimizar imagens = maior impacto em performance. 3 simples otimizacoes (serve WebP, lazy load, responsive sizes) cortam peso em 70-90% e LCP em 50%+.

Voce sai de "imagem = baixar" pra "imagem = servir formato certo, tamanho certo, com lazy loading".

O essencial 🟢

Os 3 problemas de imagem.

  1. Formato: PNG/JPEG sao ineficientes. WebP e' 30% menor, AVIF e' 50% menor.
  2. Tamanho: Imagem 4K servida pra mobile = 4x maior que precisa. Responsive serve tamanho certo.
  3. Loading: Imagem "below the fold" carrega antes do user ver = wasted bandwidth. Lazy load so carrega quando vai aparecer.

Next/Image - a forma mais facil.

import Image from "next/image";

<Image
  src="/hero.jpg"
  alt="Hero"
  width={1200}
  height={600}
  priority  // hero = LCP, sem lazy
/>

<Image
  src="/product.jpg"
  alt="Product"
  width={400}
  height={400}
  // lazy por default
/>

Next/Image faz automatic:

  • Gera WebP/AVIF (se browser suporta).
  • Serve tamanho responsivo via srcset.
  • Lazy load by default.
  • Preload com priority pra LCP.
  • Placeholder blur durante load.

Cloudflare Images - servico gerenciado.

<img
  src="https://meusite.com/cdn-cgi/image/width=800,quality=80,format=auto/hero.jpg"
  alt="Hero"
/>

Cloudflare Images transforma on-the-fly: width, quality, format. CDN global + AVIF/ WebP automatic. Preco: $5/mes basico, 100K transforms.

Formatos: WebP vs AVIF.

  • JPEG: universal, 100% suporte, baseline. Ineficiente.
  • WebP: 2014, suporte universal (Chrome, Firefox, Edge, Safari 14+). 30% menor que JPEG. Lossless + lossy.
  • AVIF: 2019, suporte crescente (Chrome, Firefox, Safari 16+). 50% menor que JPEG. Melhor qualidade visual.
  • PNG: lossless, fotos ineficientes. Use so pra logos, screenshots.

Strategy: serve AVIF se browser suporta, senao WebP, senao JPEG. Use <picture> element.

<picture>
  <source srcset="hero.avif" type="image/avif" />
  <source srcset="hero.webp" type="image/webp" />
  <img src="hero.jpg" alt="Hero" />
</picture>

next/image faz isso automatic.

Responsive images - srcset.

<img
  srcset="
    hero-400.jpg 400w,
    hero-800.jpg 800w,
    hero-1200.jpg 1200w,
    hero-2000.jpg 2000w
  "
  sizes="(max-width: 600px) 100vw, 50vw"
  alt="Hero"
/>

Browser escolhe o tamanho certo baseado em:

  • Viewport width (sizes).
  • DPR (device pixel ratio).
  • Network (SaveData).

Mobile 400px + DPR 1 = baixa hero-400.jpg (100KB). Desktop 1920px + DPR 2 = baixa hero-2000.jpg (500KB).

Lazy loading - "load so quando precisa".

<img src="hero.jpg" loading="lazy" alt="Hero" />

Browser so carrega quando imagem esta' perto da viewport (scroll). Padrao em Next/Image.

fetchpriority="high" - "esta imagem e' importante".

<img src="hero.jpg" fetchpriority="high" alt="Hero" />

Browser prioriza download. Use pra LCP image (hero, above-the-fold).

Lazy load com placeholder blur.

<Image
  src="/hero.jpg"
  alt="Hero"
  placeholder="blur"
  blurDataURL="data:image/jpeg;base64,/9j/4AAQSkZJRg..."  // tiny base64
  width={1200}
  height={600}
/>

Placeholder blur = "LQIP" (low- quality image placeholder). User ve blur → imagem real carrega = perceived performance melhor.

CLS (Cumulative Layout Shift) - por que width/height importam.

// ❌ Sem width/height = layout shift
<img src="hero.jpg" alt="Hero" />

// ✅ Com width/height = aspect ratio fixo
<Image src="/hero.jpg" alt="Hero" width={1200} height={600} />

Sem aspect ratio, browser nao sabe quanto espaco reservar = conteudo pula quando imagem carrega = CLS ruim (Google Core Web Vital). Sempre declare width e height.

Lazy load iframe (YouTube, etc).

<iframe
  src="https://www.youtube.com/embed/xyz"
  loading="lazy"
  title="Video"
></iframe>

YouTube embed = 1MB+ de JS. Lazy load = so carrega quando user scroll ate video.

decoding="async" - nao bloqueia render.

<img src="hero.jpg" decoding="async" alt="Hero" />

Decoding async = browser decodifica em background, nao bloqueia render. Default em Next/Image.

Compression: qualidade vs tamanho.

  • JPEG q=80: ~50% menor que q=100, diferenca visual minima.
  • JPEG q=60: ~70% menor, alguma perda visivel.
  • WebP q=80: ~30% menor que JPEG q=80, mesma qualidade.

Sweet spot: q=75-80. Use MochiJPG (Mozilla), Sharp, Squoosh (Google) para comprimir.

Preconnect/preload - "dica o que importa".

<head>
  <link rel="preload" href="hero.jpg" as="image" />
  <link rel="preconnect" href="https://cdn.exemplo.com" />
</head>

Preload = browser baixa antes de descobrir. Use pra LCP image. Preconnect = browser abre conexao TCP antes.

CDN image optimization.

  • Cloudflare Images: $5/mes, 100K transforms. AVIF/WebP automatic.
  • Cloudinary: free tier generoso. Transformations complexas.
  • imgix: enterprise, real-time transforms.
  • Vercel Image Optimization: built-in em Next.js, automatic.
  • Next.js Image Optimization: built-in, self-hosted.

Por que Cloudflare Images > Vercel Image: edge cache (transforma uma vez, cacheia global). Vercel: cada request = transform (pode ser caro em volume).

SVG para logos e icones.

<img src="logo.svg" alt="Logo" width="100" height="50" />

SVG = vetorial, escala perfeita, peso minimo (1-5KB vs 50KB+ pra PNG). Use pra logos, icones, illustrations. NUNCA pra fotos (use WebP/AVIF).

Imagens responsivas com art direction.

<picture>
  <source media="(max-width: 600px)" srcset="hero-mobile.jpg" />
  <source media="(min-width: 601px)" srcset="hero-desktop.jpg" />
  <img src="hero.jpg" alt="Hero" />
</picture>

Mobile: imagem cropped (foco no centro). Desktop: imagem full. Art direction = imagem diferente por viewport, NAO so tamanho.

Lighthouse image audit.

# Chrome DevTools > Lighthouse > Performance
# Audit "Properly size images" e "Serve images in next-gen formats"
# Mostra imagens nao otimizadas

Lighthouse mostra exatamente quais imagens otimizar e quanto economiza.

Aprofundamento 🟡

AVIF vs WebP - quando cada um.

  • AVIF = +20% menor que WebP, melhor qualidade visual. Suporte: Chrome 85+, Firefox 93+, Safari 16+ (2022). Em 2026, ~95% suporte.
  • WebP = +30% menor que JPEG. Suporte universal (Safari 14+, 2020). Em 2026, ~98% suporte.

Use AVIF se 95%+ users em browsers modernos. Use WebP pra max compat. Fallback JPEG sempre.

Image format detection - Accept header.

Accept: image/avif, image/webp, image/jpeg, */*

Server (Cloudflare, Vercel, Cloudinary) detecta Accept e serve formato certo. Nao precisa de <picture> se server e' inteligente.

<img srcset> vs <picture>. <img srcset> = mesma imagem, tamanhos diferentes. <picture> = imagens diferentes (art direction). Use <picture> se mobile precisa de crop diferente.

Lazy load + Intersection Observer (custom).

const observer = new IntersectionObserver((entries) => {
  entries.forEach((entry) => {
    if (entry.isIntersecting) {
      const img = entry.target as HTMLImageElement;
      img.src = img.dataset.src!;
      observer.unobserve(img);
    }
  });
});

document.querySelectorAll("img[data-src]").forEach((img) => observer.observe(img));

Custom lazy load se loading="lazy" nao basta (ex: lazy load so apos user scroll 200px).

Image sprites ainda importam? Nao mais. Use HTTP/2 multiplexing (many requests em 1 connection) + SVG (icons) + CSS sprites (mobile only). Image sprites (combined image com CSS positioning) = legacy. HTTP/2 resolve.

Image budget. Regra pratica: pagina total < 1.5MB (mobile 3G em 5s). Imagens < 800KB. Cada imagem < 200KB apos optimization. Use Lighthouse pra auditar.

PNG vs SVG - "qual pra que".

  • Logo simples (geometrico): SVG (escala perfeita).
  • Logo complexo (fotos, gradients complexos): PNG/WebP (SVG nao suporta bem fotos).
  • Icones (UI): SVG (escala, cor via CSS).
  • Screenshots: PNG (lossless, texto fica legivel).
  • Fotos: WebP/AVIF (compressao maxima).

Compressao automatica em CI.

# GitHub Actions
- name: Compress images
  run: |
    pnpm add -D sharp
    node scripts/compress-images.js
// scripts/compress-images.js
import sharp from "sharp";
import { glob } from "glob";

const files = await glob("public/images/**/*.{jpg,png}");

for (const file of files) {
  await sharp(file)
    .webp({ quality: 80 })
    .toFile(file.replace(/\.(jpg|png)$/, ".webp"));
}

CI comprime cada imagem na build = bundle otimizado.

placeholder="blur" requer blurDataURL. Next/Image gera automatic com plaiceholder lib, ou inline base64 tiny JPEG.

Leitura recomendada:

Dica: o erro mais comum em performance e' imagem nao otimizada. 1 imagem 3MB JPEG = 8s em 3G. 3 fixes (formato moderno, responsive, lazy load) = LCP < 2.5s. Use Next/Image ou Cloudflare Images - faz automatic. Nao esqueca de width/height (CLS) e priority na LCP image. Auditoria mensal com Lighthouse = garante performance mantida.

No proximo no, vamos preview environments: como cada PR ganha URL unica pra review visual, ephemeral envs, e branch URLs sem checkout local.

// Quiz

Quais as 3 otimizacoes de imagem com maior impacto em LCP e bundle size?

Escolha uma alternativa

// recursos

// avaliação da trilha

—
ainda sem avaliações