loading="lazy"生效需同时满足四条件:图片不在首屏、src为静态地址、父容器未用transform/opacity、显式设置width/height或aspect-ratio;缺一即失效。

loading="lazy"对图片生效的硬性条件
只写 loading="lazy" 不代表一定延迟加载,它必须同时满足:图片不在首屏、src 是静态地址(不能带随机参数如 ?t=1712345678)、父容器没用 transform 或 opacity 破坏滚动根检测、且显式设置了 width 和 height(或 CSS aspect-ratio)。缺任何一条,Chrome/Firefox 都可能直接发起请求。
常见踩坑点:
- 用
%或vw写宽高 → 浏览器无法在 layout 前推断尺寸,懒加载失效 - 图片包在
display: flex容器里但没设min-height→ 位置计算异常,跳过懒加载 - 首屏 Banner 图加了
loading="lazy"→ Safari 可能真就懒掉了,导致白屏 -
<picture></picture>里把loading写在<source>上 → 无效,必须写在最外层<img>标签里
iframe 的 loading="lazy"为什么经常没反应
loading="lazy" 对 <iframe> 的限制比图片更严:它只在非首屏 + 跨域 + 静态 src + 无干扰样式时才真正延迟。首屏内的 <iframe> 无论怎么写,浏览器都会强制立即加载并阻塞 DOM 解析——这不是 bug,是规范行为。
典型失效场景:
立即学习“前端免费学习笔记(深入)”;
- 广告位 iframe(如 GAM 返回的跨域地址)→ 多数浏览器忽略
loading,Network 面板里 Priority 仍是 high -
src指向同域页面(如./help.html)→ Firefox 直接不支持,Safari 15.3 及更早版本也无视 - JS 动态插入的 iframe →
loading属性在 DOM 插入后才存在,浏览器已错过解析时机 - 父容器用了
overflow: hidden或position: fixed→ 布局位置误判,懒加载逻辑被跳过
什么时候必须放弃 loading="lazy",改用 IntersectionObserver
当你要控制加载时机(比如提前 300px 触发)、处理动态插入元素、需要加载失败 fallback、或兼容 IE / 微信 iOS 旧内核时,loading="lazy" 就不够用了。这时候得手动接管生命周期。
关键实操要点:
- 初始 HTML 中彻底删掉
src,用data-src存真实地址 -
IntersectionObserver的rootMargin别设成"0px",推荐"0px 0px 200px 0px"提前加载,避免滚动过快白屏 - 回调里把
data-src赋给src后,**立刻调用observer.unobserve(element)**,否则重复触发且内存泄漏 - 加载完成后检查
iframe.contentWindow是否可访问,不能只靠onload事件
SSR 场景下懒加载最容易忽略的细节
服务端渲染时,HTML 已含完整 src,但客户端 hydration 过程中若 JS 又覆盖了 src(比如从 data-src 注入),浏览器会忽略 loading="lazy" —— 因为它只认最终生效的那个 src 值。
更隐蔽的问题是布局偏移(CLS):如果 SSR 输出的图片没预设宽高,客户端 JS 注入后尺寸撑开,页面会抖动。解决办法只有两个:
- SSR 阶段就输出
width和height属性(哪怕只是占位值) - 用 CSS
aspect-ratio+object-fit锁定容器比例,再配合srcset/sizes确保响应式正确
真正难的是平衡:原生 loading="lazy" 零成本但不可控,IntersectionObserver 可控但要自己管清理、fallback、复用逻辑。业务越复杂,越容易在“以为加了属性就完事”和“手写一堆 observer 却漏掉 unobserve”之间反复横跳。



















