所有html中的css引入一律用;@import不应出现在运行时加载链路中,只应保留在构建工具源码中用于模块组织,因其串行阻塞、不支持preload/media、无法动态注入且易导致fouc。

直接结论:所有 HTML 中的 CSS 引入,一律用 <link>;@import 不该出现在运行时加载链路里,只应留在构建工具(如 Sass/Vite)的源码中做模块组织。
浏览器加载行为差异决定性能底线
浏览器解析 HTML 时,遇到 <link rel="stylesheet"> 立即发起请求,并与其他资源(JS、图片)并行下载;而 @import 是 CSS 解析阶段才触发的规则,必须等它所在的 CSS 文件(无论是外部 .css 还是 <style></style> 块)完整下载并解析到那一行,才会开始请求被 import 的文件。
- 常见错误现象:
a.css里写@import url("b.css"); @import url("c.css");,结果是 b 下完 → 解析 → c 下完 → 解析,总耗时接近串行叠加 - 实测数据:3 层嵌套
@import在 3G 模拟下比等效<link>多出 800ms+ 首屏阻塞时间 - PageSpeed Insights 报 “Render-blocking resources” 却只看到 1 个
<link>?大概率是那个 CSS 文件内部藏了多层@import
media 和 preload 能力不可替代
<link> 支持 media 属性做条件跳过下载(比如 media="print" 或 media="(max-width: 768px)"),也支持 rel="preload" as="style" 提前拉取关键 CSS;@import 完全没有对应机制。
- 典型误用:
@import url("mobile.css") screen and (max-width: 768px);—— 语法合法,但浏览器仍会无差别下载该文件,只是不应用,浪费带宽 - 正确做法:
<link href="mobile.css" media="screen and (max-width: 768px)">,不匹配时根本不会发请求 -
rel="preload"必须配合 JS 控制时机(如 onload 时改rel="stylesheet"),@import无法 runtime 注入,也无法参与 preload 流程
JS 动态控制和构建流程必须分开看
运行时按需加载主题、暗色模式或模块样式,只能靠 JS 操作 <link> 元素:document.createElement("link") + appendChild;@import 是纯静态 CSS 规则,JS 动态插入无效。
- 以下写法不生效:
const style = document.createElement('style'); style.innerHTML = '@import url("theme-dark.css");'; document.head.appendChild(style); - 原因:浏览器忽略运行时动态插入的
@import,只在初始 CSS 解析阶段处理 - 构建工具(Sass/Less/Vite)中写的
@import没问题——它在编译期就被展开合并了,最终输出的仍是单个或多个<link>可加载的文件
真正容易被忽略的点是:哪怕你没手写 @import,只要用了某些老旧的构建配置或第三方 CSS 包(比如未经过现代打包器处理的 legacy UI 库),它们内部可能仍含有多层 @import。上线前务必用 DevTools 的 Network 面板检查实际加载链路,确认没有隐式串行依赖。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











