图片降级核心是确保用户始终看到可用图片而非白屏或叉号,src必须指向静态高可用资源(如CDN占位图),禁止空值、错误路径或动态接口地址;picture需严格按type兼容性排序,onerror须内联防死循环,lazy加载需双src兜底。

图片降级不是“让图不显示”,而是确保用户在任何网络、设备或 JS 状态下,至少看到一张可用的图——否则就是白屏或叉号。
src 必须永远指向一个真实可加载的资源
80% 的降级失败,根源是 src 本身不可用:空值、"#"、相对路径错误、动态接口地址(如 /api/image?uid=123)在断网或 SSR 失败时直接失效。浏览器不会因为 src 加载失败就自动切到 data-src 或 ,它只发一次请求,失败就停。
-
src应该是静态、高可用地址:CDN 托管的占位图(如/img/placeholder.svg)、LQIP 模糊图,或 SSR 渲染出的真实小图 - 禁止写
src=""、src="broken.jpg"(且该文件实际不存在)、src="./images/xxx.jpg"(本地能跑,部署后因路由重写 404) - SSR 时,
src值必须由服务端直接写出,不能依赖客户端 JS 注入
picture + source 的结构和顺序不能错
不是“多图任选”,而是严格按顺序匹配: 从上到下检查,第一个 media 为真且 type 被支持的才生效;其余全忽略。如果全不匹配,浏览器仍会尝试加载底部 的 src——但若这个 src 也 404,就只剩 alt 文本。
-
必须按兼容性从强到弱排:type="image/avif"→type="image/webp"→ 最后才是 JPEG fallback -
type值必须和真实 MIME 类型一致,"image/webp"错一个字母都不认 - 底部
是必需子元素,它的src必须独立可访问(不能带查询参数,不能是相对路径错误的地址)
onerror 只能内联,且必须防死循环
onerror 不响应空 src、CORS 拦截、服务器返回 200 占位图等场景——它只对“请求发出后返回非 2xx 或网络中断”触发。动态绑定(如 img.addEventListener('error', ...))在 Safari 和旧 Edge 中大概率不触发;全局 error 事件监听也捕获不到它(不冒泡)。
- 唯一可靠写法是 HTML 内联:
onerror="this.src='/img/fallback.png'; this.onerror=null;" - 更稳妥写法:
onerror="if (!this.src.includes('fallback')) this.src='/img/fallback.png'; this.onerror=null;" - 如果连 fallback 图都不可信,直接用 base64:
onerror="this.src='data:image/svg+xml;base64,PHN2Zy...'; this.onerror=null;"
loading="lazy" 的降级必须有双 src 路径
浏览器不支持 loading="lazy" 时,它不会读取 data-src,也不会报错,只是当这个属性不存在,然后照常加载 src。如果此时 src 是空、占位图路径错误、或被 display: none 隐藏,结果就是白屏。
- 必须同时维护两套状态:
src指向可用占位图(如 1px GIF 或 LQIP),data-src存高清图地址 -
data-src必须静态写在 HTML 中(不能靠 JS 注入),否则断网时 JS 加载失败,data-src就丢了 - 关键图片(如商品主图、头图)跳过懒加载:直接写死
src,不加loading="lazy",也不设data-src
最容易被忽略的是:CSS 层面没设宽高或 aspect-ratio,图片加载前容器塌陷,布局抖动;或者用 display: none 包裹懒加载容器,Safari 和多数 Android WebView 会直接跳过该元素,后续即使显示也无法补救。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











