rel="stylesheet"是硬性门槛,漏写或设错值将导致CSS不加载;必须插入head中防FOUC;需去重避免重复请求;onload/onerror须显式绑定且跨域失败需预检。

rel="stylesheet" 是硬性门槛,不设等于白干
浏览器只认 rel="stylesheet" 这个值,设成 rel="style"、rel="css" 或漏写,link 标签就只是个普通 HTML 元素,不会触发任何 CSS 下载或解析。这是最常被跳过的一步,也是所有后续逻辑失效的根源。
实操建议:
- 必须显式赋值 link.rel = 'stylesheet'
- 不要依赖默认值或“应该能推断”这种想法
- 若兼容老旧 IE(如 IE8),建议补上 link.type = 'text/css',现代浏览器可省略
插入位置决定是否 FOUC,head 是唯一稳妥选择
把 link 插入 document.body 后,部分浏览器(尤其是 Safari 和旧版 Chrome)会延迟应用样式,导致页面先渲染无样式内容,再突然闪动(FOUC)。这不是 bug,是规范行为——CSS 需在 DOM 构建早期介入渲染流程。
实操建议:
- 一律用 document.head.appendChild(link)
- 避免插到 body 末尾或用 insertBefore 找错锚点
- 若需控制加载顺序(比如确保在某库 CSS 之后),可加 id 或 data-loaded 标记,按需调整插入位置
重复插入 href 相同的 link 会导致样式覆盖或冗余请求
没有去重逻辑时,路由切换、组件多次挂载、热更新等场景下,同一份 CSS 可能被反复插入。结果可能是:两次请求、样式规则叠加冲突、甚至因加载时机差异引发布局抖动。
实操建议:
- 插入前先查 document.querySelector(`link[href="${href}"]`)
- 对带版本号或时间戳的 URL(如 theme.css?v=2.1.0),需统一生成策略,避免语义相同但字符串不同
- 若需替换样式(如切主题),先 oldLink.remove() 再插入新 link,不要仅靠后加载覆盖
onload/onerror 不是 Promise,跨域失败还静默丢弃
link.onload 和 link.onerror 是事件,不是可 await 的 Promise;直接写 loadCSS(url).then(...) 会报错。更麻烦的是:跨域 CSS 加载失败(如 403、CORS 拒绝)根本不会触发 onerror,只在控制台报 warning,JS 层完全感知不到。
立即学习“前端免费学习笔记(深入)”;
实操建议:
- 必须显式绑定两个事件:link.onload = () => {...}、link.onerror = () => {...}
- 跨域资源建议配合 fetch(href, { method: 'HEAD', mode: 'no-cors' }) 预检(注意 no-cors 下无法读响应状态,仅用于探测连接通路)
- 生产环境若用 CDN,优先走同域代理或开启 CORS,别依赖静默失败兜底
动态插入本身很简单,真正复杂的是加载状态的可观测性与竞态控制——尤其当多个模块各自尝试加载同一份 CSS,或样式就绪时机直接影响 JS 行为时,事件监听和去重必须成为标配,不能当作“可选优化”。


















