为什么需要图片懒加载
图片是网页中体积最大的资源类型之一。根据 HTTP Archive 的统计,图片平均占网页总重量的 50% 以上。在一个典型的新闻或电商页面中,可能有数十张图片同时加载,这会导致首屏加载时间显著增加、带宽浪费和数据流量消耗。图片懒加载(Lazy Loading)的核心思想是:只加载用户当前可见区域(视口)内的图片,其他图片在用户滚动到附近时才加载。这种方法可以大幅减少初始页面加载时间,提升用户体验和核心 Web 指标(Core Web Vitals)。
一、技术概述
1.1 工作原理
懒加载的技术实现基于以下几个关键步骤:
- 替换图片源:在 HTML 中,将
<img>标签的src属性替换为占位图或空白,并将真实图片 URL 存储在data-src等自定义属性中 - 监测滚动位置:监听页面滚动事件,或使用 Intersection Observer API 监测图片元素是否进入视口
- 加载真实图片:当图片进入视口时,将
data-src的值赋给src属性,触发浏览器加载 - 加载完成处理:图片加载完成后,移除占位样式,显示真实图片
1.2 性能收益
| 场景 | 未使用懒加载 | 使用懒加载 | 提升 |
|---|---|---|---|
| 首屏加载时间 | 3.5s | 1.8s | 提升 48% |
| 页面总传输量 | 2.8MB | 0.6MB | 减少 78% |
| Lighthouse Performance 评分 | 62 | 94 | 提升 32 分 |
二、实现方案
2.1 原生懒加载(推荐)
从 Chrome 76 开始,浏览器原生支持图片懒加载,只需在 <img> 标签中添加 loading="lazy" 属性:
<img src="example.jpg" loading="lazy" alt="示例图片" />
<!-- 支持 iframe 懒加载 -->
<iframe src="example.html" loading="lazy"></iframe>
优点:零 JavaScript 代码,浏览器自动优化加载时机,性能最佳。
缺点:不支持所有浏览器(Safari 需 15.4+)。
2.2 Intersection Observer API
对于需要更精细控制的场景,可以使用 Intersection Observer API:
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);
}
});
});
document.querySelectorAll('img.lazy').forEach(img => {
imageObserver.observe(img);
});
| 方案 | 复杂度 | 性能 | 可维护性 | 适用场景 |
|---|---|---|---|---|
| 原生 lazy 属性 | 低 | 极高 | 高 | 通用场景 |
| Intersection Observer | 中 | 高 | 中 | 需要自定义加载效果 |
| 第三方 JS 库 | 低 | 中 | 中 | 兼容老旧浏览器 |
2.3 第三方库方案
- Lozad.js:轻量级(1KB),基于 Intersection Observer
- lazysizes:功能最全,支持响应式图片和自动计算
- vanilla-lazyload:简单易用,支持图片、iframe 和视频
2.4 生产环境推荐组合
不用二选一,可以组合使用:原生属性打底、Observer 做增强。一个省心的模板:
<img
src="placeholder.svg"
data-src="photo-800.jpg"
data-srcset="photo-400.jpg 400w, photo-800.jpg 800w, photo-1200.jpg 1200w"
data-sizes="(max-width: 600px) 100vw, 800px"
loading="lazy"
decoding="async"
width="800" height="450"
class="lazy"
alt="文章配图"
/>
width/height 固定宽高比(配合 CSS 的 aspect-ratio)在图片加载前就占好位置,避免布局偏移拉低 CLS;decoding="async" 让解码不阻塞主线程;srcset/sizes 让浏览器按视口宽度选合适尺寸,移动端不再下载桌面大图。Observer 代码只负责把 data-src/data-srcset 替换成真实地址。
三、高级优化技巧
// 结合占位图技术(BlurHash)
const img = new Image();
img.onload = () => {
// 先显示模糊缩略图
placeholder.style.filter = 'blur(20px)';
// 加载完成后淡入高清图
highResImg.classList.add('loaded');
};
img.src = highResUrl;
四、注意事项
- 首屏图片不应用懒加载:首屏可视区域内的图片应使用正常加载
- 预留图片占位空间:设置宽高比(aspect-ratio)防止布局偏移
- 考虑 SEO 影响:确保搜索引擎爬虫能抓取到图片
- 兼容性处理:为不支持原生懒加载的浏览器提供降级方案
- 图片解码优化:使用
decoding="async"属性异步解码图片
关于占位空间再补充一点:除了固定 width/height,还可以用 CSS 的 aspect-ratio 配 content-visibility,后者能让视口外的区块跳过渲染,进一步加快滚动加载。两者同时生效时,页面几乎不会因为图片逐个加载而上下跳动,用户体验会明显更稳。
常见疑问
- 懒加载会不会影响 SEO:Google 明确表示支持
loading="lazy"也能抓取懒加载图片;关键是 DOM 里要给真实 URL(src或可解析的data-src),别让图片完全靠 JS 动态插入。 - 首屏图要懒加载吗:不要,首屏内图片应立即加载,否则会拖慢 LCP。
- 懒加载和 CDN 冲突吗:不冲突,反而建议配合 CDN 使用——懒加载减少请求数,CDN 提高命中率。
一个真实案例
一个摄影博客的图集页有 40 张 2MB 大图,改动前首屏传输量约 8MB,移动端打开要等十几秒。做了三件事后首屏降到 1.2MB:缩略图用 loading="lazy" + srcset 按宽度出图、首屏外的图交给 Observer 按需加载、列表页改用模糊占位图(LQIP)。结果是 Lighthouse Performance 从 54 分升到 91 分,跳出率一个季度里降了 6 个百分点。懒加载不是“加一个属性”就完事,要跟图片压缩、响应式尺寸一起做才有效果。
五、总结
图片懒加载是提升网页性能最简单有效的优化手段之一。对于现代浏览器,推荐直接使用 loading="lazy" 属性;如果需要自定义加载效果或支持更多功能,Intersection Observer API 提供了足够的灵活性和性能。无论采用哪种方案,合理配置懒加载都能显著改善用户体验和核心性能指标。
参考:MDN loading 属性 https://developer.mozilla.org/zh-CN/docs/Web/HTML/Reference/Attributes/loading ;MDN Intersection Observer https://developer.mozilla.org/zh-CN/docs/Web/API/Intersection_Observer_API ;web.dev 关于图片懒加载 https://web.dev/articles/browser-level-image-lazy-loading