JA EN ZH

图像懒加载实现指南 - loading=lazy 与 IntersectionObserver 的选择

· 9 分钟阅读

为什么需要图像懒加载

懒加载延迟加载视口外的图像,仅在用户即将看到时才开始加载。这显著减少初始页面加载时间和带宽消耗。

收益:

  • 减少初始加载量:首屏外的图像不在页面加载时请求,加速 DOMContentLoaded 和 LCP
  • 节省带宽:用户可能不会滚动到页面底部,未查看的图像无需加载
  • 减少并发请求:避免数十张图像同时请求导致的带宽竞争

注意:首屏图像(Above the fold)不应懒加载,否则会延迟 LCP。懒加载仅用于首屏以下的图像。

原生 loading=lazy - 最简单的实现

HTML 原生的 loading="lazy" 属性是最简单的懒加载实现,无需 JavaScript。

用法:<img src="photo.jpg" loading="lazy" alt="描述" width="800" height="600">

浏览器行为:

  • 浏览器自动判断图像是否在视口附近,决定何时开始加载
  • 具体的「提前加载距离」由浏览器决定(Chrome 约 1250px-2500px,取决于网络速度)
  • 不可自定义触发距离

优势:

  • 零 JavaScript,最简单的实现
  • 浏览器原生优化,性能最好
  • 自动处理各种边缘情况(打印、搜索引擎爬虫等)

局限:

  • 无法自定义触发距离(rootMargin)
  • 无法添加加载动画或占位效果
  • 无法实现渐进式加载(LQIP → 全图)
  • 必须设置 width/height 防止 CLS

IntersectionObserver - 灵活的自定义方案

IntersectionObserver API 提供高性能的元素可见性检测,可实现完全自定义的懒加载逻辑。

基本实现:

  • 图像初始不设置 src,将真实 URL 存在 data-src 属性
  • 创建 IntersectionObserver 监听图像元素
  • 元素进入视口时,将 data-src 赋值给 src 触发加载
  • 加载完成后取消观察该元素

自定义选项:

  • rootMargin: "200px":提前 200px 开始加载(预加载缓冲区)
  • threshold: 0:元素刚进入视口即触发(默认)
  • 可配合加载动画:src 赋值前显示骨架屏,加载完成后淡入

优势:完全可控的触发时机、可添加加载动画、支持 LQIP 渐进加载、可实现优先级控制。

两种方案的对比与选择

根据项目需求选择合适的懒加载方案,或组合使用。

对比:

  • 实现复杂度:loading=lazy(零代码)vs IO(需要 JS 实现)
  • 可定制性:loading=lazy(不可定制)vs IO(完全可定制)
  • 加载动画:loading=lazy(无)vs IO(可自定义)
  • 触发距离:loading=lazy(浏览器决定)vs IO(rootMargin 自定义)
  • 兼容性:两者都有良好的现代浏览器支持

推荐策略:

  • 简单博客/文档站:直接使用 loading=lazy,零成本获得懒加载
  • 图片密集型应用:IntersectionObserver + LQIP + 加载动画
  • 电商产品列表:IO + 优先级控制(首屏产品优先加载)

防止布局偏移(CLS)的最佳实践

懒加载图像如果没有预留空间,加载完成时会导致页面布局偏移(CLS),严重影响用户体验和 Core Web Vitals 分数。

解决方案:

  • 明确 width/height:始终在 img 标签上设置宽高属性,浏览器据此预留空间
  • aspect-ratio CSS:img { aspect-ratio: 16/9; width: 100%; height: auto; }
  • 容器占位:用固定宽高比的容器包裹图像,图像用 object-fit 填充

LQIP(低质量占位图):

  • 内联极小的模糊缩略图(如 20x15px 的 Base64)作为占位
  • 全图加载完成后替换占位图,使用 CSS 过渡实现平滑切换
  • 占位图体积 < 1KB,可内联在 HTML 中无需额外请求

框架集成与高级模式

主流前端框架都提供了图像懒加载的内置支持或推荐方案。

Next.js Image:

  • <Image> 组件默认启用懒加载
  • 自动生成 srcset 和 sizes
  • 内置 blur placeholder 支持
  • 首屏图像设置 priority 属性跳过懒加载

React:

  • 自定义 Hook:useIntersectionObserver 封装懒加载逻辑
  • 库:react-lazy-load-image-component

Vue:

  • v-lazy 指令(vue-lazyload 库)
  • Nuxt Image 组件内置懒加载

高级模式:

  • 优先级队列:根据图像在视口中的位置排序加载优先级
  • 网络感知:慢速网络时加载更小的图像或降低预加载距离
  • 空闲时预加载:使用 requestIdleCallback 在空闲时预加载即将可见的图像

Related Articles

响应式图像实现指南 - srcset、sizes 与 picture 元素完全指南

响应式图像的完整实现指南。涵盖 srcset 属性、sizes 属性、picture 元素的艺术指导及构建流程中的自动化生成。

Web 图像文件大小优化策略 - 在保持质量的同时减小体积

系统讲解 Web 图像文件大小优化技术。涵盖格式选择、分辨率优化、元数据清理、CDN 分发优化和自动化质量管理。

浏览器图像处理的工作原理 - Canvas API、ImageData 与 Web Workers 指南

技术详解浏览器中的客户端图像处理。学习使用 Canvas API 进行像素操作、ImageData 结构、Web Workers 离线程处理以及 OffscreenCanvas 的使用方法。

Core Web Vitals 与图像优化 - 改善 LCP、CLS 和 INP 的实用方法

图像优化对 Core Web Vitals 的影响及改善方法。涵盖 LCP 加速策略、CLS 防止、INP 优化及懒加载最佳实践。

Web 图像性能审计 - Core Web Vitals 改善实践指南

Web 图像性能审计的完整方法论。涵盖审计工具与指标、LCP 优化、CLS 防止、传输大小优化及持续监控体系。

图像加载策略设计 - 掌握 preload、fetchpriority 和 decoding

系统讲解图像加载策略的设计。涵盖 preload 预加载、fetchpriority 优先级控制、decoding 解码策略和综合加载方案。

Related Terms