图片太多拖慢首屏:用 IntersectionObserver 做懒加载

举报
静水流深-云海 发表于 2026/09/19 17:47:34 2026/09/19
【摘要】 用 IntersectionObserver 实现图片懒加载

以前做过一个活动页,二十多张商品图,浏览器一打开就闷头往下请求,进度条转半天,用户还没划到底就跑了。流量浪费不说,首屏也被拖累。后来给图片加了懒加载,滚到哪儿加载哪儿,第一屏的请求数直接从二十多个降到三四个,效果是肉眼可见的。做这个最舒服的办法就是 IntersectionObserver,不用监听滚动、不用自己算位置。

一、先看最省事的做法

现代浏览器原生就支持懒加载,一行属性搞定:

<img loading="lazy" alt="商品图" width="400" height="300">

浏览器自己会在图片接近视口时才去请求。兼容性到今天已经很够用了,如果你的需求就是"滚动到才加载",优先用它,别折腾。那什么时候要自己写?比如要在加载前后做动画、要控制提前加载的距离、要懒加载背景图或者下一页数据,原生属性就管不到了,得请 IntersectionObserver 出场。

二、自己撸一个懒加载

思路是:真实地址先存在 data-src 里,src 放一张占位图;观察每张图,一旦它进入视口(或接近视口),把 data-src 换成真 src,然后停止观察它。

<img data-src="real-1.jpg" alt="商品图" width="400" height="300">
const io = new IntersectionObserver((entries, observer) => {
  entries.forEach(entry => {
    if (!entry.isIntersecting) return;
    const img = entry.target;
    img.src = img.dataset.src;
    img.removeAttribute('data-src');
    observer.unobserve(img);
  });
}, { rootMargin: '200px 0px', threshold: 0 });

document.querySelectorAll('img[data-src]').forEach(img => io.observe(img));

回调拿到的是一批 entry,isIntersecting 为 true 表示元素露出来了。rootMargin 给视口上下各扩出 200 像素,也就是说图还在屏幕外两百像素时就开始加载,等用户滚到它时基本已经就位,不会出现一片空白等着。unobserve 很关键,加载完就取消观察,避免滚来滚去重复触发。

三、踩坑提醒

第一,也是最阴的一条:图片必须有确定的宽高。如果不写 width / height 也没用 CSS 的 aspect-ratio 撑住,加载前所有 img 高度都是 0,一股脑堆在页面顶部,IntersectionObserver 判断它们全都在视口里,于是瞬间全部触发,懒加载直接失效。我当时排查半天才发现是这个原因。

第二,别忘了 unobserve。不取消观察的话,用户上下滚动会反复进入回调,白白浪费判断开销,而且万一后面又改了 src 还会重复请求。

第三,rootMargin 别设太大。提前量给到 200 到 300 像素比较合适,设成几千像素等于没懒加载,白白把请求发出去了。

第四,首屏那几张图别懒加载。首屏大图用 loading=“lazy” 或 IO 延迟,会把最大内容绘制(LCP)时间推后,反而让首屏指标变差。正确做法是首屏图直接给真实 src,甚至可以加 fetchpriority=“high”,首屏之外的再懒加载。

第五,兼容性要兜底。老一点的 Safari 和 IE 不支持 IntersectionObserver,上线前确认目标用户的浏览器版本,需要兼容就引 polyfill,或者简单降级:检测不到就一次性把所有 data-src 换成 src。

第六,背景图同样能懒加载,原理一样,给容器加一个 class,回调里把 background-image 的 URL 换上去就行。

四、什么时候不该用

图片总数本来就不多(三五张)的时候别加,省下的那点请求抵不上多出来的一套逻辑。页面很短、用户不需要滚动的场景也没必要。真正划算的是长列表、图库、活动页、无限滚动的信息流这类"图片多且首屏看不到全部"的场景。

五、小结

懒加载的核心就是一句话:滚到再加载。能用一个属性解决就别写 JS,原生 loading=“lazy” 已经覆盖大多数情况;需要更精细的控制(提前距离、加载动画、背景图、埋点)时才上 IntersectionObserver。动手前记住图片要给宽高,这条踩过一次就忘不掉。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。