多图页面降级需确保断网、JS失败等所有异常下用户至少看到占位图或小图;src必须有效(如1px GIF),data-src须静态写入HTML;关键图禁用懒加载;picture需type、sizes、正确顺序及img兜底;IntersectionObserver初始化代码须内联。

多图页面的降级不是“加个 fallback 就完事”,而是要确保断网、JS 失败、老浏览器、CSS 隐藏等所有异常路径下,用户至少能看到占位图或真实小图——否则白屏就是默认结果。
loading="lazy" 降级失败时图片全白,怎么办
根本原因:只写了 loading="lazy",但 src 是空值或无效路径,data-src 又没在 HTML 中静态存在。浏览器不支持该属性时,就按普通 <img> 处理,而此时没有可用的 src,直接白屏。
-
src必须始终指向一个可用资源:推荐 1px GIF(data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==)或 SSR 渲染出的真实小图,绝不能留空 -
data-src必须在 HTML 源码里写死,不能靠 JS 动态注入;否则断网时 JS 加载失败,data-src根本不存在 - 关键图片(如商品主图、头图)跳过懒加载:直接写
src,不加loading="lazy",也不设data-src - 避免用
display: none包裹图片容器——Safari 和多数 Android WebView 会直接跳过该元素,后续显示也无法触发加载
picture + srcset 降级失效,加载错尺寸或空白
仅写 srcset 不够,没 sizes 或 media,浏览器只能瞎猜宽度,手机可能拉取 3840w 版本;缺 type 属性,Safari 会跳过 <source> 导致空白。
-
<source>的type属性不能省:type="image/avif"是 Safari 识别 AVIF 的唯一依据 -
sizes必须显式声明,例如sizes="(max-width: 768px) 100vw, (min-width: 1920px) 50vw, 300px",否则默认按100vw猜 - 顺序必须是现代格式优先:
<source type="image/avif">→<source type="image/webp">→<img src="fallback.jpg"> -
<img>标签必须存在且带有效src和alt,它是所有不支持<picture>的浏览器唯一兜底项
IntersectionObserver 初始化失败,图片全不加载
JS 文件加载失败(弱网、拦截器、CDN 故障),整个懒加载逻辑就归零。不能把初始化逻辑放在外部 .js 文件里等网络拉取。
立即学习“前端免费学习笔记(深入)”;
- 核心初始化代码必须内联:
<script>if ('IntersectionObserver' in window) { /* observer 创建逻辑 */ } else { document.querySelectorAll('img[data-src]').forEach(i => i.src = i.dataset.src); }</script> - 用
rootMargin: '100px'提前加载,防滚动过快导致视口一闪而过 - 加载后立刻调用
observer.unobserve(img),避免重复触发;已加载的图片加data-loaded="true"标记跳过二次处理 - 不要监听
scroll事件做 fallback——它本身就会引发重排重绘,性能更差
WebP / AVIF 图片在旧浏览器中直接空白
直接写 <img src="xxx.webp"> 在 Safari 13.1 前、旧版 Edge 中就是空白。浏览器不识别格式,也不会自动 fallback 到其他源。
- 必须用
<picture>结构,每个<source>显式声明type,并以<img>为最终兜底 - Service Worker 动态返回 WebP 时,必须检查请求头:
event.request.headers.get('Accept')是否含image/webp,否则返回原格式 - AVIF 在低端 Android 上解码卡顿明显,上线前务必在真实设备(如 Redmi Note 9)上测滚动帧率,别只信 Lighthouse 数据
- 本地开发时路径错位会导致静默失败,用
Array.from(document.images).filter(i => i.naturalWidth === 0)快速定位未加载图
最常被绕过的环节是:服务端没预生成多尺寸图,前端却拼命配 srcset 和 sizes;或者 CSS 把图片容器设成 display: none,以为“后面再 show”就行——其实懒加载早已被跳过,再也唤不醒。



















