@import强制暂停CSSOM构建,因浏览器必须等当前CSS文件下载解析到该行才发起导入请求,导致资源瀑布流、DOMContentLoaded延迟、FOUC等问题。

为什么@import会强制暂停CSSOM构建
浏览器解析 CSS 时,遇到 @import 就必须停下:它不会发起请求,直到当前 CSS 文件**已完整下载并开始解析到那一行**。这意味着 main.css 里第一行是 @import url("reset.css");,那整个 reset.css 的下载、解析、注入 CSSOM 都得等 main.css 下载完才启动——而 main.css 后面的规则、甚至后续 <script></script> 标签,全被卡住。
常见错误现象包括:DOMContentLoaded 延迟 300ms+、Network 面板里 CSS 请求的 Initiator 显示为 stylesheet(而非 parser)、Lighthouse 报 “Render-blocking resources” 却找不到明显大文件。
为什么预加载器完全看不到@import
HTML 解析器有个后台线程叫 preload scanner,它在解析 HTML 的同时,会提前扫描出所有 <link rel="stylesheet"> 并立刻并发请求。但 @import 是 CSS 语法,不是 HTML 资源声明——它藏在 CSS 文件里,preload scanner 根本不读 CSS 内容,所以对它视而不见。
结果就是:reset.css 和 utils.css 这些本该和 HTML 并行下载的资源,被迫排在 main.css 之后,形成“瀑布流”。HTTP/2 多路复用也救不了:请求能并行,但**解析仍强制串行**。
立即学习“前端免费学习笔记(深入)”;
- 构建工具(如 Vite)里用了
@import "./theme.css";,要检查最终产出的dist/main.css是否还存在明文@import—— 搜索一下最直接 - 如果用了 Sass,确认
sass-loader没退化到旧模式(比如关了api: 'modern'),否则编译后可能漏掉内联
@import的media参数根本不管下载时机
写 @import url("dark.css") (prefers-color-scheme: dark);,浏览器依然会在首屏初始化阶段无差别下载 dark.css。它的 media 只控制规则是否“生效”,不控制是否“下载”。这和 <link rel="stylesheet" href="dark.css" media="(prefers-color-scheme: dark)"> 完全不同——后者会被 preload scanner 识别为非关键资源,跳过阻塞,甚至不发请求(取决于浏览器实现)。
同理:@import url("print.css") print; 看似只用于打印,实际照样拖慢首屏;真正安全的写法永远是 <link> + media 属性。
嵌套@import让FOUC和白屏更刺眼
两层嵌套(main.css → theme.css → reset.css)在弱网下常导致 CSSOM 构建延迟 600ms+。DOM 内容先渲染、样式后到,用户看到「文字乱排→突然整齐」的闪烁(FOUC),移动端尤其明显。
更隐蔽的问题:@import 在 <style></style> 标签内比外链 CSS 更晚执行,且无法用 JS 监听 onload,document.styleSheets 里也查不到中间态;跨域 @import 还会触发 CORS 预检,进一步拉长等待时间。
真正容易被忽略的是:你改完了开发代码,却没打开最终上线的 CSS 文件确认——只要里面还躺着一行 @import url(...),白屏就还在那儿等着你。


















