
动态创建 <link rel="stylesheet"> 会触发加载吗
会,但仅当标签被插入到 document.head(或任意 document 中的父节点)后才真正发起网络请求。单纯用 document.createElement('link') 创建而不挂载,样式不会加载,也不会报错。
常见错误现象:link 元素创建后没调用 appendChild(),结果页面样式没变,控制台也无请求、无报错,容易误以为“失败了”或“被拦截了”。
- 必须设置
rel="stylesheet"和href(绝对路径或相对路径,后者以当前 HTML 文档为基准) - 推荐在
link插入前监听load和error事件,避免“静默失败” - 注意:Firefox 和 Safari 对
link.onload支持更严格,建议统一用addEventListener('load', ...)
怎么判断 CSS 是否已加载完成
不能靠 link.sheet 是否为 null 来判断——它在加载中、加载失败、跨域等情况下都可能是 null,且部分浏览器延迟赋值。可靠方式只有事件驱动。
使用场景:比如模块 A 依赖样式就绪后再渲染 UI;或做 loading 状态管理。
立即学习“Java免费学习笔记(深入)”;
- 监听
link.addEventListener('load', handler)是唯一可信赖的成功信号 -
link.addEventListener('error', handler)必须监听,尤其当href路径拼错、服务未启动、CORS 阻止时,控制台可能只显示“Failed to load resource”,不抛 JS 错误 - 不要用
setTimeout等待,CSS 加载时间不可控,且可能因缓存、HTTP/2 推送等大幅波动
多个 CSS 并行加载时如何保证顺序执行
CSS 文件本身没有执行顺序问题,但如果你的 JS 逻辑依赖某份样式就绪后才运行(例如读取 getComputedStyle),那加载顺序就变成关键路径。
参数差异:浏览器对 link 的加载是并行的,但解析和应用是按插入 DOM 的顺序进行的(前提是同为 rel="stylesheet")。所以顺序取决于你调用 appendChild() 的先后。
- 如果需串行(如 a.css → b.css → 执行回调),可用 Promise 链:每个
link的load事件 resolve 后再创建下一个 - 如果只是“全部加载完再执行”,推荐用
Promise.all(loads),每个 load 是一个监听load事件的 Promise - 避免把
link插入body或文档末尾——某些浏览器可能延迟应用,务必插到head
动态加载 CSS 在现代框架里的兼容性坑
Vue / React 组件级样式(如 <style scoped>、CSS Modules)通常由构建工具处理成内联或 hash 命名,直接动态加载外部 CSS 文件会绕过这些机制,导致类名冲突或样式隔离失效。
性能影响:动态 link 不参与 webpack/vite 的依赖图分析,无法被 tree-shaking、预加载提示(<link rel="preload">)、HTTP/2 push 感知,可能造成重复加载或缓存失效。
- Webpack 项目慎用动态
href,尤其是带变量的路径(如./themes/${theme}.css),会导致所有主题文件全被打包进主 bundle - Vite 中若用
import('./theme.css'),会走其 CSS 拆包逻辑;而手动createElement('link')则完全脱离构建流程 - 移动端 WebView(如微信内置浏览器)对动态
link的 onload 触发有时延,建议加 50ms 超时兜底
link 标签——否则换肤、主题切换时老样式还在内存里占着,sheet.cssRules 可能泄露,而且多次插入相同 href 的 link 会重复下载。










