Safari 完全不触发 link.onload 事件,需结合 onerror、样式检测和超时三重保障:onload/onerror 触发即响应,否则轮询 getComputedStyle(testEl).opacity 等稳定属性,5 秒超时。

link.onload 在 Safari 中根本不会触发
别被“现代浏览器都支持”骗了。Chrome 93+、Firefox 65+、Edge(Chromium)确实能可靠触发 link.onload,但 Safari(包括 iOS 17 / macOS 14 及后续版本,截至 2026 年 5 月仍无变化)**完全不派发 load 事件**——这不是 bug,是 Safari 主动选择不实现该行为。只靠 onload 判断“加载成功”,在 Safari 下 Promise 永远 pending,页面逻辑卡死。
onload 必须在插入 DOM 前绑定,否则 Chrome/Firefox 也可能失效
动态插入 CSS 时,事件监听器必须在 document.head.appendChild(link) 之前设置。如果先 append 再赋值 link.onload,Chrome 和 Firefox 在缓存命中或快速加载场景下会直接跳过事件触发——规范明确要求:事件监听需在元素加入文档树前就位。
- ✅ 正确顺序:
link.onload = handler; document.head.appendChild(link); - ❌ 错误顺序:
document.head.appendChild(link); link.onload = handler; - 即使加了
setTimeout延迟赋值,也无法修复这个竞态问题
仅靠 onerror 不足以判断“失败”,它可能永远不触发
link.onerror 在 404、CORS 阻止、MIME 类型错误(如返回 HTML 页面)、CSS 语法错误时会触发,但它有严重盲区:
- 网络中断(请求未发出或超时)→
onerror不触发 - Safari 加载失败时,
onerror可能触发,也可能不触发(行为不稳定) - 服务端返回 200 但内容为空或乱码 →
onerror不触发,但样式实际无效
所以单靠 onerror 无法覆盖所有失败路径,也不能作为“加载中”的反向信号。
立即学习“前端免费学习笔记(深入)”;
真正可靠的方案:事件 + 样式检测 + 超时三重保障
生产环境必须组合使用三层判断,任一成功即视为 CSS 引入成功:
-
link.onload触发 → 立即 resolve -
link.onerror触发 → 立即 reject - 无论事件是否发生,在插入后启动轮询:
getComputedStyle(testEl).opacity是否等于预设值(如"0.001"),间隔用requestAnimationFrame,超时设为 5 秒
关键细节:
- 测试元素必须已挂载到
document.body,不能仅创建未 append - 避免用
color或display这类易被继承/重置的属性,优先选font-family: "css-loaded-9b3"或margin-top: 9999px - 不要轮询
document.styleSheets[i].cssRules,跨域样式表会抛SecurityError,且访问cssRules可能强制重排
最常被忽略的一点:Safari 的不可观测性不是临时缺陷,而是长期策略。你写的检测逻辑,必须默认它“从不触发 onload”,再往上叠加兜底,而不是把它当作可选优化。


















