link.onload不能单独作为可靠完成信号,因其不区分成功与失败,旧版Firefox/WebKit不触发,且CSS解析错误、CORS拒绝等静默问题均不阻止其触发;应结合轮询link.sheet与cssRules、事件监听及超时兜底。

link.onload 在现代浏览器中基本可用,但不能单独依赖它判断“加载完成”——因为 onload 不区分成功与失败,且旧版 Firefox / WebKit 甚至不触发该事件。
为什么 link.onload 不能直接用作可靠完成信号
规范里写得很清楚:load 事件只在“获取资源及其关键子资源”完成后触发,但“CSS 解析错误”“跨域样式表读取被阻止”这类问题不会触发 error,也不会阻止 load。也就是说:
-
link.onload触发 ≠ 样式已生效或可被 JS 访问 -
link.onerror只对网络层失败(404、连接中断)有效,对 CSS 语法错误、CORS 拒绝完全静默 - IE 和老版 Safari/Chrome 中
onload根本不支持,必须降级轮询
link.sheet 和 sheet.cssRules 是更底层的判断依据
真正能反映“样式是否就绪”的是 DOM 中 link.sheet 是否存在,以及其 cssRules 是否可读。但要注意浏览器差异和安全限制:
- WebKit(Chrome/Safari ≤ v16):只要
link.sheet存在,就认为加载完成(即使内容为空) - Firefox(≤ v89):需访问
link.sheet.cssRules,但跨域时会抛SecurityError(ex.code === 1000),此时应视为“加载完成但不可读” - 现代 Chromium/Firefox:同源下
cssRules长度 > 0 才算真正可用;若为 0,可能是空文件或解析失败 - 所有浏览器:首次访问
sheet.cssRules会强制触发样式计算,可能引发 layout thrashing,轮询间隔至少设为10ms
推荐的监听模式:事件 + 轮询 + 超时兜底
不要只押注一种方式。一个健壮的 loadCSS 实现应同时覆盖三类情况:
立即学习“前端免费学习笔记(深入)”;
- 优先监听
link.addEventListener("load", handler, { once: true })—— 现代浏览器最快路径 - 立即启动轮询:检查
link.sheet是否存在,再尝试读cssRules(带try/catch) - 设置总超时(如
5000ms),超时后无论是否就绪都执行回调,避免阻塞后续逻辑 - 回调函数应接收两个参数:
(err, link),其中err为null表示“尽力而为后认为可用”,非null表示明确失败(如 404 或超时)
容易被忽略的是:轮询期间如果页面被用户切到后台,setTimeout 可能被节流,导致检测延迟翻倍;生产环境建议用 requestIdleCallback 替代高频 setTimeout,或至少把轮询间隔从 1ms 改为 16ms(一帧)。


















