loading="lazy" 并非总生效,仅对初始HTML中存在、不在首屏、具明确宽高、父容器无干扰样式的<img>有效;缺宽高、父容器含transform/overflow:hidden、JS动态插入、错放于<source>、绝对定位占位等均导致退化为eager加载。

直接加 loading="lazy" 不等于图片真会懒加载——它只对「初始 HTML 就存在、不在首屏、有明确宽高、父容器没干扰样式」的 <img> 生效;其他情况大概率失效,甚至拖慢首屏。
为什么 loading="lazy" 写了但图片还是全量加载?
浏览器只在首次 layout 后批量检查可视性,以下任一条件不满足,就会退化为 eager 加载:
-
<img>缺少width和height属性(或设为%/vw),导致无法推断尺寸 - 图片被包裹在
overflow: hidden、transform、contain: layout或will-change: transform的父容器中 - 图片是 JS 动态插入的(如 Vue
v-for、Reactmap()渲染),不属于初始 HTML - 用了
<picture>但把loading="lazy"错写在<source>上(该属性只对<img>有效) - 首屏判定出错:比如用
position: absolute; top: -9999px占位,浏览器认为它“已渲染但不可见”,不触发懒加载
loading="eager" 必须显式写在首屏关键图上
别依赖默认行为——Chrome 默认 eager,但 Safari(尤其 iOS 16.3 及更早)可能把没声明的图也懒掉,导致 banner 白屏。
- 首屏 Hero 图、Logo、核心按钮图标,必须同时满足:
loading="eager"+<link rel="preload" as="image" href="hero.webp"> -
preload的href必须和<img>的src完全一致,否则浏览器当两个资源处理,重复下载 - 禁止给
loading="lazy"的图再preload——预加载和懒加载逻辑冲突,反而增加竞争
自定义懒加载用 IntersectionObserver 怎么写才不翻车?
需要 fallback、提前加载、LQIP 占位或兼容老浏览器时才上手写,但容易卡主线程或触发重排:
宝塔面板11.3.0是一款针对Linux服务器设计的可视化管理工具,通过重构核心模块实现资源占用显著降低,尤其适合低配置服务器环境。它将复杂的命令行操作转化为直观的图形界面,帮助开发者快速完成网站部署、环境配置及日常运维工作,无需专业技术背景即可高效管理服务器。
立即学习“前端免费学习笔记(深入)”;
- 初始
<img src="placeholder.svg" width="300" height="200">,必须设宽高,防布局抖动 - 真实地址存
data-src,回调里只做两件事:img.src = img.dataset.src+observer.unobserve(img) - 监听前先过滤已在视口内的元素:
Array.from(images).filter(img => img.getBoundingClientRect().top ,避免刚进页面就批量触发 - 别在回调里调 AJAX、改 class、触发动画或操作其他 DOM——这些都会打断渲染帧
srcset 和 sizes 配错会让懒加载白忙活
只写 srcset 不配 sizes,浏览器根本不知道图片占多宽,只能瞎猜,移动端常拉取 2000w 桌面图。
-
sizes值必须反映**实际占位宽度**,不是视口宽度。例如侧边栏内图固定占 300px,就写sizes="300px" - 响应式布局写法:
sizes="(max-width: 768px) 100vw, 33vw",对应不同断点下的容器宽度 -
srcset中的w描述符(如800w)必须和原图真实宽度一致,否则切换逻辑失效 -
<picture>中<source>只能有srcset和type,src必须且只能出现在最底层<img>标签里,且兜底格式得是 JPEG/PNG
真正难的不是加个属性,而是判断哪张图该 lazy、哪张该 eager、哪张该 preload,以及怎么让 srcset 和懒加载逻辑协同不打架——这些边界条件一旦漏掉一个,性能优化就变成负优化。


















