原生 loading="lazy" 仅对初始 html 中存在、不在首屏、有明确 width/height、且父容器无 transform/overflow: hidden 干扰的 生效;其余情况静默退化为 eager。

loading="lazy"加了但图片还是全量加载,为什么
浏览器只对「初始 HTML 就存在、不在首屏、有明确 width 和 height、父容器没 transform/overflow: hidden 干扰」的 <img> 生效;其他情况会静默退化为 loading="eager"。
常见失效点包括:
-
<img>缺少width和height属性(设成100%或vw也不行),Safari 15.4+ 直接拒懒加载 - 把
loading="lazy"错写在<source></source>上——该属性只对最外层<img>有效 - 图片由 Vue/React 动态渲染(如
v-for或map()),不属于初始 HTML,Chrome 可能立即加载,Firefox 可能延迟白屏 - 父容器用了
transform: translateZ(0)或contain: layout,干扰 Intersection Observer 检测逻辑 - 用
position: absolute; top: -9999px占位,浏览器判定“已渲染但不可见”,不触发懒加载
srcset + sizes 必须和 loading="lazy" 配套使用
懒加载触发时,浏览器才开始选图。如果没配 srcset 和 sizes,它就只能拉 src 里的 fallback 图——大概率是桌面大图,移动端白耗流量。
正确组合方式:
-
srcset列出多个宽度候选:srcset="cat-400w.webp 400w, cat-800w.webp 800w, cat-1200w.webp 1200w" -
sizes告诉浏览器当前视口下该选哪个:sizes="(max-width: 480px) 100vw, (max-width: 1024px) 50vw, 800px" -
src仅作降级兜底,必须是小尺寸图(如cat-400w.webp),不能留空或指向大图 - 所有尺寸单位统一用
w(源图固有宽度),别混用x或px
首屏关键图必须显式设 loading="eager"
别依赖默认行为——Chrome 默认 eager,但 Safari(尤其 iOS 16.3 及更早)可能把没声明 loading 的图也懒掉,导致 Banner 白屏。
首屏 Hero、Logo、头像等必须同时满足:
-
loading="eager"显式声明 -
<link rel="preload" as="image" href="hero.webp">放在中,且href和<img>的src完全一致 - 禁用
decoding="async"(首屏图解码不能异步,否则 LCP 可能卡顿) - 宽高用 HTML 属性写死,避免 SSR 渲染时无占位
自定义懒加载用 IntersectionObserver 怎么写才不卡
只在需要 fallback、LQIP 占位、或兼容老浏览器时才手写;否则原生 loading="lazy" 更稳。写错容易主线程卡死或内存泄漏。
安全写法要点:
- 初始化时先过滤已在视口内的元素:
if (el.getBoundingClientRect().top ,避免刚进页面就批量触发 - 回调里只做两件事:
el.src = el.dataset.src,然后observer.unobserve(el) - 别在回调里调 AJAX、改 class、触发动画或重排布局
-
<img>必须带width和height(哪怕只是占位尺寸),防 CLS - 动态插入的新图,插入后立刻
observer.observe(newImg),别等滚动再触发
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











