Q28 · 通用优化策略
图片优化有哪些常见手段?如何实现懒加载?
⚡ 速记答案(30 秒)
- 格式选择:WebP/AVIF 比 JPEG/PNG 小 30-50%
- 尺寸适配:使用 srcset 和 sizes 响应式图片
- 懒加载:loading="lazy" 或 Intersection Observer
- 压缩:使用 imagemin、tinypng 等工具
- CDN:图片上 CDN + 缓存策略
📖 详细讲解
图片优化策略
1. 格式选择
| 格式 | 特点 | 适用场景 |
|---|---|---|
| JPEG | 有损压缩 | 照片 |
| PNG | 无损、透明 | 图标、截图 |
| WebP | 更小、支持动画 | 通用 |
| AVIF | 最小、新格式 | 现代浏览器 |
| SVG | 矢量 | 图标、图形 |
2. 响应式图片
<img
src="image-800.jpg"
srcset="
image-400.jpg 400w,
image-800.jpg 800w,
image-1200.jpg 1200w
"
sizes="(max-width: 600px) 400px, 800px"
/>3. 懒加载
原生支持:
<img src="image.jpg" loading="lazy" />优化效果
| 优化项 | 节省 |
|---|---|
| WebP 替换 | 30-50% |
| 合适尺寸 | 50-80% |
| 懒加载 | 首屏 50% |
💻 代码示例
Intersection Observer 懒加载
function LazyImage({ src, alt, ...props }: React.ImgHTMLAttributes<HTMLImageElement>) {
const imgRef = useRef<HTMLImageElement>(null);
const [isLoaded, setIsLoaded] = useState(false);
useEffect(() => {
const img = imgRef.current;
if (!img) return;
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
// 进入视口,开始加载
img.src = src || '';
observer.unobserve(img);
}
});
},
{ rootMargin: '50px' } // 提前 50px 开始加载
);
observer.observe(img);
return () => observer.disconnect();
}, [src]);
return (
<img
ref={imgRef}
alt={alt}
style={{ opacity: isLoaded ? 1 : 0, transition: 'opacity 0.3s' }}
onLoad={() => setIsLoaded(true)}
{...props}
/>
);
}Next.js Image 组件
import Image from 'next/image';
// Next.js 自动优化:
// - 自动选择 WebP/AVIF
// - 自动生成多尺寸
// - 自动懒加载
// - 自动占位符
function OptimizedImage() {
return (
<Image
src="/photo.jpg"
alt="Photo"
width={800}
height={600}
placeholder="blur"
blurDataURL="data:image/jpeg;base64,..."
priority={false} // 非首屏图片
/>
);
}面试技巧:回答性能问题时,先说指标和标准,再讲优化手段,最后结合实际项目经验。