onerror常不触发是因为它仅响应请求发出后的失败,对src=""、CORS阻塞、200占位图等静默场景完全无效;可靠写法是内联onerror="this.src='/img/fallback.png'; this.onerror=null"。

src 必须指向静态高可用资源,否则浏览器连降级机会都不给——这是所有图片降级失效的根源。
为什么 onerror 经常不触发
onerror 只响应“请求发出后失败”,对以下情况完全静默:src=""、src="#"、CORS 阻塞、服务器返回 200 状态码的占位图(哪怕内容是空的)、src 指向一个 404 接口(如 /api/image?uid=123)。
- 唯一可靠写法是内联:
onerror="this.src='/img/fallback.png'; this.onerror=null" - 更稳妥加判断防死循环:
onerror="if (!this.src.includes('fallback')) this.src='/img/fallback.png'; this.onerror=null" - 动态绑定
img.onerror在 Safari 和旧 Edge 中大概率不触发;document.addEventListener('error')也捕获不到(它不冒泡)
<picture> 结构错一行就退化成纯文本
<picture> 是唯一不依赖 JS、不发多余请求、SEO 友好的原生降级方案,但结构极其敏感。
-
<source>必须按支持强度从强到弱排列:type="image/avif"→type="image/webp"→ 最后才是<img src="fallback.jpg"> -
<img>不是第 N 个<source>,它是必需子元素,且其src必须独立可访问(不能带查询参数,不能是相对路径错误,如..images/logo.jpg少了/) - 服务器返回的
Content-Type必须与type完全一致;Nginx 未配types { image/webp webp; }会导致 .webp 被当成application/octet-stream,浏览器静默跳过
srcset + sizes 能替代多数降级逻辑
现代浏览器(Chrome 38+、Firefox 32+、Safari 8.1+)对 srcset 和 sizes 支持稳定,IE11 等不支持者会自动回退至 src,无需冗余 <picture> 或 JS。
立即学习“前端免费学习笔记(深入)”;
-
src是必填兜底,所有浏览器都认;srcset和sizes被忽略时自动回退到它 - 错误示范:
<picture>套三层<source>只为做尺寸切换——其实一行<img>就够:<img src="hero-480.jpg" srcset="hero-480.jpg 480w, hero-960.jpg 960w" sizes="(min-width: 768px) 960px, 100vw"> - 不要用
background-image模拟响应式图片:SEO 归零、无障碍失效、打印样式失控、无法触发loading="lazy"
首屏图和头像必须绕过懒加载且自带真实占位
loading="lazy" 单独使用会白屏:浏览器不支持时忽略该属性,若 src 为空或无效,断网或 JS 失败时图片无资源可加载。
- 首屏关键图必须写死
src,不能只靠data-src或 JS 补全 - 头像等用户可见核心图,
<img>的src应直接指向 CDN 上的真实小图(如/assets/default-avatar.jpg),而非占位 SVG 或 base64 - 用
aspect-ratio预留空间防重排;旧版 Safari 回退用height: 0; padding-bottom: 56.25%
最易被忽略的一点:SSR 渲染时,src 值必须由服务端直接写出,不能依赖客户端 JS 注入——否则断网时连占位图都出不来。



















