图片失效降级需分层控制:src必须指向静态高可用资源(如cdn占位图),结构须合规(为必需兜底且独立可访问),onerror必须内联并立即切断事件链(this.onerror=null),缺一不可。

图片失效降级不是“加个onerror就行”,而是必须分层控制:路径要对、src要可用、<picture></picture>结构要合规、onerror要防死循环,缺一不可。
确保 src 永远指向一个真实可加载的资源
80% 的“图片白屏”问题,根源是 src 本身为空、写错、或指向了断网即失效的动态地址(比如 /api/image?uid=123&format=webp)。浏览器不会因为 src 失效就自动切到 data-src 或 <source></source>——它只管发请求,失败了就停在那里。
-
src必须是静态、稳定、高可用的 URL:推荐用 CDN 托管的占位图(如/img/placeholder.svg)或业务默认图(如/img/avatar-default.png) - 绝对禁止
src=""、src="broken.jpg"(且该文件实际不存在)、src="./images/xxx.jpg"(本地开发能跑,部署后因路由重写失效) - SSR 渲染时,
src值必须由服务端直接写出,不能依赖客户端 JS 注入——否则断网时连占位图都出不来
用 <picture></picture> 实现格式回退,但顺序和兜底必须严格
<picture></picture> 是唯一不依赖 JS、不发多余请求、SEO 友好的原生方案,但它对结构极其敏感。写错一行,整块就退化成纯文本。
-
<source></source>必须按浏览器支持强度从强到弱排列:type="image/avif"→type="image/webp"→ 最后才是<img src="fallback.jpg"> -
<img>不是第 N 个<source></source>,它是<picture></picture>的必需子元素,且它的src必须独立可访问(不能带查询参数,不能是相对路径错误的地址) - 所有
srcset中的图片必须尺寸一致、裁剪比例一致,否则切换时会拉伸或跳变 - IE 或旧 WebView 会忽略整个
<picture></picture>标签,只渲染<img>——这反而是优势,前提是你的<img src>真的能加载
onerror 只能内联写,且必须立即切断自身
动态绑定 img.onerror 在 Safari 和旧 Edge 中大概率不触发;document.addEventListener('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/png;base64,iVBORw0KGgo...'; this.onerror=null" -
onerror不响应空src、CORS 阻塞、服务器返回 200 占位图等场景——它只管“请求发出后失败”。别指望它覆盖所有失效情况
断网和弱网下最容易被忽略的陷阱
很多降级逻辑在 DevTools 里关掉网络模拟看似正常,一到真机弱网或拦截器环境就崩,原因往往不在 JS,而在 DOM 和 CSS 层。
-
display: none的容器里放loading="lazy"图片?Safari 和多数 Android WebView 直接跳过,后续display: block也不会补触发 - CSS
aspect-ratio或宽高未设?图片加载前容器无尺寸,布局抖动(CLS),用户感知就是“闪一下再出来” -
fetchpriority="high"没打在首屏关键图上?文本先渲染,图片卡在低优先级队列里,用户看到的是“有字无图” - 背景图失效排查要进 Network 面板看请求 URL,不是看 HTML 里写的对不对——CSS 文件里的
url()是以 CSS 文件为基准解析的,不是 HTML
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











