首屏关键图必须加 loading="eager",包括Banner主图、网站Logo、用户头像、核心操作按钮图标,且需显式声明并配合完全一致的 preload;loading="lazy" 失效常见于缺宽高、transform容器、JS动态插入、写在<source>或<table>内;真正生效需满足初始HTML存在、默认不在首屏、宽高可推断、不脱离文档流、声明viewport;精细控制应改用IntersectionObserver。

哪些图片必须加 loading="eager"
首屏关键图不加 loading="eager",Safari(尤其 iOS 16.3 及更早)可能直接跳过加载,导致白屏或图标缺失。这类图包括:Banner 主图、网站 Logo、用户头像、核心操作按钮图标。
必须同时满足两个条件:
-
loading="eager"显式写在标签上(不能依赖默认行为) - 配合
<link rel="preload" as="image" href="xxx">,且href必须和<img>的src完全一致;否则浏览器当两个资源处理,重复下载
禁止对 loading="lazy" 的图再 preload——预加载和懒加载逻辑冲突,反而增加请求竞争。
loading="lazy" 失效的硬性条件
写了属性但图片仍全量加载,大概率是以下任一条件被触发:
立即学习“前端免费学习笔记(深入)”;
-
<img>缺少width和height(内联或 CSS 均可),浏览器无法推断尺寸,部分 Safari 直接降级为 eager - 父容器用了
transform、will-change: transform或overflow: hidden,破坏滚动根检测,Chrome 会认为“不可滚动”,永远不触发 - 图片是 JS 动态插入的(如 React
map()、Vuev-for渲染),不属于初始 HTML,浏览器不纳入原生懒加载队列 - 错把
loading="lazy"写在<source>上——该属性只对<img>有效,<picture>内需写在最内层<img> - 图片位于
<table>内部(<td>或<tr>中),Chrome 对表格子元素的懒加载支持极弱,基本失效
如何让 loading="lazy" 真正生效
不是加了就完事,得满足浏览器的“信任前提”:
- 图片必须在初始 HTML 中存在(SSR 渲染后已输出),且默认不在首屏内(
getBoundingClientRect().top > window.innerHeight) - 确保宽高可推断:用内联
width/height,或 CSSaspect-ratio+width: 100%防止布局偏移 - 避免脱离文档流:不用
position: absolute或fixed占位(哪怕top: -9999px),浏览器可能判定为“已渲染但不可见”,跳过懒加载检查 - 移动端必须声明
<meta name="viewport">,否则 WebView 可能忽略该属性或降级处理
示例有效写法:<img src="product.jpg" loading="lazy" width="320" height="240" alt="商品图">
什么时候该放弃 loading="lazy",改用 IntersectionObserver
原生 lazy 是声明式、零成本的基线优化,但控制粒度太粗。遇到以下情况,必须上 JS 方案:
- 需要提前加载(比如离视口还有 300px 就发起请求),
rootMargin: "300px"比浏览器内部约 1250px 的固定阈值更可控 - 要支持加载失败 fallback(如显示占位图、重试按钮),
onerror无法和懒加载时机联动 - 图片在
<table>内无法移出,或父容器必须用transform且不能改 - 需配合 LQIP(低质量占位图)、解码控制(
decoding="async")或响应式srcset精细调度
注意:不要混用——已设 loading="lazy" 的 <img> 再套 IntersectionObserver,容易引发重复请求或竞态。



















