图片优化策略

WebP、雪碧图、Base64、懒加载、响应式图片的使用场景和实现

问题

前端图片优化有哪些常用策略?分别适用于什么场景?

解答

1. WebP 格式

WebP 比 JPEG/PNG 体积小 25-35%,支持透明和动画。

<!-- 使用 picture 元素做格式降级 -->
<picture>
  <source srcset="image.webp" type="image/webp">
  <source srcset="image.jpg" type="image/jpeg">
  <img src="image.jpg" alt="fallback">
</picture>
// 检测 WebP 支持
function checkWebpSupport() {
  const canvas = document.createElement('canvas');
  return canvas.toDataURL('image/webp').indexOf('data:image/webp') === 0;
}

2. 雪碧图 (CSS Sprites)

将多个小图标合并成一张图,减少 HTTP 请求。

/* 雪碧图使用 */
.icon {
  background-image: url('sprites.png');
  background-repeat: no-repeat;
}

.icon-home {
  width: 24px;
  height: 24px;
  background-position: 0 0;
}

.icon-user {
  width: 24px;
  height: 24px;
  background-position: -24px 0;
}

.icon-settings {
  width: 24px;
  height: 24px;
  background-position: -48px 0;
}

3. Base64 内联

小图片转 Base64 直接嵌入,省去请求。适合 < 2KB 的图片。

/* CSS 中使用 Base64 */
.logo {
  background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==');
}
// JS 转换图片为 Base64
function imageToBase64(file) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => resolve(reader.result);
    reader.onerror = reject;
    reader.readAsDataURL(file);
  });
}

4. 懒加载

图片进入视口时才加载,减少首屏请求。

<!-- 原生懒加载 -->
<img src="image.jpg" loading="lazy" alt="lazy image">
// Intersection Observer 实现懒加载
function lazyLoadImages() {
  const images = document.querySelectorAll('img[data-src]');
  
  const observer = new IntersectionObserver((entries, observer) => {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        const img = entry.target;
        img.src = img.dataset.src;
        img.removeAttribute('data-src');
        observer.unobserve(img); // 加载后停止观察
      }
    });
  }, {
    rootMargin: '50px' // 提前 50px 开始加载
  });

  images.forEach(img => observer.observe(img));
}

document.addEventListener('DOMContentLoaded', lazyLoadImages);
<!-- 配合使用 -->
<img data-src="real-image.jpg" src="placeholder.jpg" alt="lazy">

5. 响应式图片

根据设备屏幕加载不同尺寸的图片。

<!-- srcset + sizes -->
<img 
  src="small.jpg"
  srcset="small.jpg 400w,
          medium.jpg 800w,
          large.jpg 1200w"
  sizes="(max-width: 600px) 400px,
         (max-width: 1000px) 800px,
         1200px"
  alt="responsive image">
<!-- picture 元素实现艺术指导 -->
<picture>
  <!-- 移动端:裁剪后的竖版图 -->
  <source media="(max-width: 768px)" srcset="mobile.jpg">
  <!-- 平板:中等尺寸 -->
  <source media="(max-width: 1200px)" srcset="tablet.jpg">
  <!-- 桌面端:完整横版图 -->
  <img src="desktop.jpg" alt="art direction">
</picture>
<!-- 高清屏适配 -->
<img 
  src="image.jpg"
  srcset="image.jpg 1x,
          image@2x.jpg 2x,
          image@3x.jpg 3x"
  alt="retina image">

策略选择参考

策略适用场景注意事项
WebP所有图片需要格式降级
雪碧图小图标集合HTTP/2 下收益降低
Base64< 2KB 小图增加 CSS/HTML 体积
懒加载长页面、图片列表首屏图片不要懒加载
响应式不同设备展示需准备多套图片

关键点

  • WebP 体积更小,用 <picture> 做格式降级兼容旧浏览器
  • 雪碧图减少请求数,但 HTTP/2 多路复用后优势减弱
  • Base64 适合极小图片,过大会增加文档体积且无法缓存
  • 懒加载用 loading="lazy" 或 Intersection Observer,首屏图片除外
  • 响应式图片用 srcset + sizes 让浏览器自动选择合适尺寸