只有标签支持loading="lazy"属性,必须将其加在上而非或;混用原生懒加载与intersectionobserver会导致重复请求;不继承data-*属性,需单独设置;首屏图应移除loading属性并配合。

picture 标签本身不支持 loading="lazy" 属性
<source></source> 标签没有 loading 属性,规范中也不允许;只有最内层的 <img> 可以加 loading="lazy"。但很多人误以为给 <picture></picture> 加上该属性就能生效,结果发现懒加载没触发——其实是写错了位置。
浏览器只读取 <img> 的 loading 值,<source></source> 完全被忽略。所以正确写法是:
<picture><source media="(min-width: 1024px)" srcset="hero-lg.webp"><source media="(min-width: 768px)" srcset="hero-md.webp"> @@##@@ </source></source></picture>
- 必须把
loading="lazy"放在<img src="hero-sm.jpg" srcset="hero-sm.jpg" loading="lazy" alt="hero">上,不是<picture></picture>或<source></source> -
src和srcset都要保留在<img>中,作为 fallback 和响应式基础 - 若用 WebP + JPEG 回退,
<source type="image/webp"></source>不影响loading行为,仍由<img>控制
同时用 picture + IntersectionObserver 容易重复请求
当页面已启用原生 loading="lazy",又手动用 IntersectionObserver 监听同一张图并设置 img.src,Chrome 和 Safari 可能并发发起两次请求:一次是浏览器原生触发的 src 加载,另一次是 JS 赋值后触发的二次加载。
典型表现是 Network 面板里出现两个相同 URL 的 200 请求,或图片一闪再闪。根本原因是:<img> 已有 src,且 loading="lazy" 生效,JS 不该再动 src。
- 方案一(推荐):纯原生,只用
loading="lazy"+srcset+sizes,彻底移除 JS 懒加载逻辑 - 方案二(兼容旧浏览器):完全移除
loading="lazy",改用data-src和data-srcset存原始地址,Observer 回调中统一赋值img.src和img.srcset - 切勿混用:不要一边留着
loading="lazy",一边在 JS 里写img.src = img.dataset.src
picture 中的 source 不继承 data-* 属性,需单独处理
如果要用 JS 方案控制懒加载(比如需要提前 200px 加载),<source></source> 标签不会自动继承 <img> 上的 data-srcset,也不会响应 dataset 读取。这意味着你不能只给 <img> 设 data-srcset 就完事。
真实场景中,<source></source> 的 srcset 必须也存一份可读的原始值,否则 Observer 触发时无法还原多格式资源。
- 正确做法:给每个
<source></source>加data-srcset,和它自身的srcset值一致 - Observer 回调中,遍历
picture.querySelectorAll('source'),把source.dataset.srcset赋给source.srcset - 最后再处理
<img>的src和srcset,确保 fallback 通路完整 - 注意 Safari 对空
srcset的敏感:赋值前检查是否为"",避免设成无效字符串
首屏关键图用 picture 时 loading="eager" 不够保险
即使写了 loading="eager",某些 SSR 场景(如 Next.js App Router)可能在 hydration 前就把 <img> 当作非关键资源跳过预加载,导致首屏图延迟渲染。更稳妥的做法是:不依赖 loading 属性,而是靠构建时标记 + CDN 预加载策略。
- 对真正首屏图,去掉
loading属性(默认即 eager),并确保src是最小可用尺寸的 fallback - 在
中加<link rel="preload" as="image" href="hero-sm.jpg">,强制提前拉取 - 若用
<picture></picture>,preload 只能指向<img>的src,无法 preload<source></source>—— 所以 fallback 图必须足够好 - 服务端渲染时,避免框架自动给所有
<img>注入loading="lazy",需按 class 或 data- 属性白名单控制
实际最难处理的是 <source></source> 与 <img> 的状态同步问题:宽高丢失、srcset 错位、sizes 不匹配,任一出错都会让懒加载变成布局抖动加载。别只盯着“能不能加载”,先确保“加载完不跳”——这才是 <picture></picture> 整合懒加载时最常被跳过的环节。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











