图片破损时仅靠onerror替换src会丢alt、触发死循环或fallback失败;必须内联写法+立即this.onerror=null阻断,推荐用类名切换配合CSS伪元素显示alt,并确保src指向高可用静态资源。

图片破损时只靠 onerror 替换 src,大概率会丢掉 alt 文本、触发死循环、或 fallback 图本身也加载失败——降级不是“换一张图”,而是保留语义、阻断异常、提供视觉兜底。
onerror 必须内联 + 立即切断事件链
动态绑定 img.onerror 在 Safari、旧 Edge 中不触发;document.addEventListener('error') 也捕获不到它(不冒泡)。唯一可靠的是 HTML 内联写法,且不加防护就会无限重试。
- 错误写法:
onerror="this.src='/fallback.jpg'"→ 万一/fallback.jpg也 404,会反复触发onerror - 正确写法:
onerror="this.src='/fallback.jpg'; this.onerror=null" - 更稳妥写法:
onerror="if (!this.src.includes('fallback')) this.src='/fallback.jpg'; this.onerror=null",避免 fallback 自身出错时循环 - 极端情况(连 fallback 都不可信):
onerror="this.src='data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg=='; this.onerror=null"
破损后仍要显示 alt 文本,不能只塞占位图
直接替换 src 会导致 alt 消失,用户完全不知道原图想表达什么。设计师忍不了裂图,但程序员更不该牺牲可访问性。
- 推荐做法:用
onerror添加类名,而非替换src:onerror="this.classList.add('error'); this.onerror=null" - CSS 中用
::before渲染占位背景,::after显示alt:img.error::after { content: attr(alt); } - 确保
alt可读:设置font-size、background半透明遮罩、line-height控制垂直居中
src 本身不能是空、无效路径或动态地址
80% 的“白屏”问题,根源不在 onerror 是否生效,而在于 src 初始值就不可加载——浏览器根本不会等到失败才触发 onerror,它只管发请求,失败了就停在那里。
立即学习“前端免费学习笔记(深入)”;
- 禁止:
src=""、src="#"、src="./images/xxx.jpg"(本地能跑,部署后因路由重写失效) - 禁止:
src="/api/image?uid=123"(断网或服务不可用时立即失效) - 必须:
src指向静态高可用资源,如 CDN 托管的占位图:src="/img/placeholder.svg"或业务默认图:src="/img/avatar-default.png" - SSR 渲染时,
src值必须由服务端直接写出,不能依赖客户端 JS 注入
CSS fallback 要防住空 src 和 CORS 场景
onerror 不响应空 src、CORS 阻塞、服务器返回 200 占位图等场景——它只对“HTTP 请求失败且状态码非 200”敏感。这时候就得靠 CSS 提前兜底。
- 给所有
img设置默认背景:img { background: #f5f5f5 url(/img/broken.svg) no-repeat center / contain; } - 用
object-fit: contain防止拉伸,配合固定宽高容器保持比例 - 对已知可能失败的图片(如用户上传头像),额外加类:
img.user-avatar { background-image: url(/img/avatar-placeholder.png); } - 注意:CSS fallback 无法替代
alt,只是视觉补救;语义层仍需靠 HTML 属性和onerror类名协同
真正难的不是写几行 onerror,而是让 src 始终真实可加载、让 alt 始终可见、让 CSS fallback 不依赖 JS 执行时机——这三者缺一不可,漏掉任何一个,断网或弱网下用户看到的就是一片空白或一个红叉。



















