Imagens são frequentemente o maior componente de uma página web:
Formato desenvolvido pelo Google, oferece:
<picture>
<source srcset="imagem.webp" type="image/webp">
<img src="imagem.jpg" alt="Descrição">
</picture>
Formato mais moderno e eficiente:
<picture>
<source srcset="imagem.avif" type="image/avif">
<source srcset="imagem.webp" type="image/webp">
<img src="imagem.jpg" alt="Descrição">
</picture>
Para fotografias e imagens complexas:
# Usando imagemagick
convert imagem.jpg -quality 85 -strip imagem-otimizada.jpg
# Usando sharp (Node.js)
const sharp = require('sharp');
sharp('imagem.jpg')
.jpeg({ quality: 85, mozjpeg: true })
.toFile('imagem-otimizada.jpg');
Para gráficos, logos, ícones:
# PNG sem perda
pngquant --quality=65-80 imagem.png
# SVG otimizado
svgo imagem.svg
Nunca use imagens maiores que o necessário:
<!-- ❌ Ruim - imagem 2000px usada em 400px -->
<img src="foto-2000px.jpg" width="400" alt="Foto">
<!-- ✅ Bom - imagem redimensionada -->
<img src="foto-400px.jpg" width="400" alt="Foto">
// Redimensionar no servidor (Node.js com sharp)
sharp('imagem-original.jpg')
.resize(400, 400, {
fit: 'cover',
position: 'center'
})
.jpeg({ quality: 85 })
.toFile('imagem-400px.jpg');
Use srcset e sizes para diferentes tamanhos de tela:
<img
srcset="
imagem-400px.jpg 400w,
imagem-800px.jpg 800w,
imagem-1200px.jpg 1200w
"
sizes="(max-width: 600px) 400px,
(max-width: 1200px) 800px,
1200px"
src="imagem-800px.jpg"
alt="Descrição">
Carregue imagens apenas quando necessário:
<!-- Lazy loading nativo -->
<img
src="imagem.jpg"
loading="lazy"
alt="Descrição">
<!-- Com Intersection Observer (fallback) -->
<img
data-src="imagem.jpg"
class="lazy"
alt="Descrição">
// Intersection Observer para lazy loading
const lazyImages = document.querySelectorAll('img.lazy');
const imageObserver = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
img.classList.remove('lazy');
observer.unobserve(img);
}
});
});
lazyImages.forEach(img => imageObserver.observe(img));
/* ❌ Ruim - imagem grande */
.hero {
background-image: url('hero-2000px.jpg');
}
/* ✅ Bom - imagem otimizada e responsiva */
.hero {
background-image: image-set(
url('hero-400px.webp') 1x,
url('hero-800px.webp') 2x
);
background-image: url('hero-800px.jpg'); /* fallback */
}
.hero {
background-image: url('hero-placeholder.jpg');
}
.hero.loaded {
background-image: url('hero-full.jpg');
}
// Carregar imagem de fundo quando visível
const hero = document.querySelector('.hero');
const imageObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('loaded');
imageObserver.unobserve(entry.target);
}
});
});
imageObserver.observe(hero);
Para ícones, use SVG sprites:
<svg class="icon">
<use href="#icon-home"></use>
</svg>
<svg style="display: none;">
<symbol id="icon-home" viewBox="0 0 24 24">
<path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"/>
</symbol>
</svg>
Prefira SVG para ícones:
<!-- Preload da imagem LCP -->
<link rel="preload" as="image" href="hero-image.jpg" fetchpriority="high">
<!-- Prefetch de imagens provavelmente necessárias -->
<link rel="prefetch" as="image" href="next-page-hero.jpg">
// Webpack com imagemin
const ImageminPlugin = require('imagemin-webpack-plugin').default;
module.exports = {
plugins: [
new ImageminPlugin({
pngquant: { quality: [0.65, 0.8] },
mozjpeg: { quality: 85 }
})
]
};
// Vite com vite-imagetools
import { imagetools } from 'vite-imagetools';
export default {
plugins: [
imagetools({
defaultDirectives: (url) => {
if (url.searchParams.has('webp')) {
url.searchParams.set('format', 'webp');
}
return new URLSearchParams({
quality: '85'
});
}
})
]
};
<picture>
<!-- Formatos modernos primeiro -->
<source
srcset="
hero-400px.avif 400w,
hero-800px.avif 800w,
hero-1200px.avif 1200w
"
type="image/avif"
sizes="(max-width: 600px) 400px,
(max-width: 1200px) 800px,
1200px">
<source
srcset="
hero-400px.webp 400w,
hero-800px.webp 800w,
hero-1200px.webp 1200w
"
type="image/webp"
sizes="(max-width: 600px) 400px,
(max-width: 1200px) 800px,
1200px">
<!-- Fallback -->
<img
srcset="
hero-400px.jpg 400w,
hero-800px.jpg 800w,
hero-1200px.jpg 1200w
"
sizes="(max-width: 600px) 400px,
(max-width: 1200px) 800px,
1200px"
src="hero-800px.jpg"
alt="Hero image"
loading="eager"
fetchpriority="high"
width="1200"
height="600">
</picture>