在中小型网站向组件化演进的过程中,样式文件往往会膨胀到难以阅读。CSS原生提供的@import规则,可以让一个样式表在内部声明引入另外的样式文件,从而把庞大的单文件拆成多个职责单一的模块,例如将颜色变量、基础重置、按钮样式分开放置,再统一聚合。

@import的基本语法与工作方式
@import必须写在样式表的最前面(除了@charset之外),其后跟一个URL值或字符串,以及可选的媒体查询条件。当浏览器解析到这条规则时,会向服务器发起对应文件的请求,并在当前样式表中插入该文件的内容。如下面这段代码,把三个不同用途的样式模块引入到主文件中:
/* main.css */
@import url("variables.css");
@import url("reset.css");
@import url("buttons.css") screen and (min-width: 768px);
body {
font-family: "PingFang SC", sans-serif;
}
需要注意,如果@import出现在其他普通规则之后,大部分浏览器会直接忽略它。这是因为CSS规范规定@import属于条件组的导入,必须在所有其他规则之前。很多初学者把@import随手写在底部,结果拆分完全没生效,样式错乱却找不到原因。
另外,@import支持媒体类型与媒体特性,这意味着你可以针对不同的设备条件加载不同的样式片段。例如只在打印时引入打印样式,能减少屏幕浏览时的无用请求。但这种按条件拆分若使用过多,也会让关键渲染路径变复杂。
与link标签加载的差异及性能影响
在HTML里用<link>标签引入多个CSS文件,和用@import在CSS内部引入,看起来结果相似,但加载机制不同。link是HTML解析时并行请求的,而@import是在CSS文件下载并解析后,才发现还要再去拉取其他文件,形成串行依赖。
| 方式 | 请求时机 | 并行性 | 适用场景 |
|---|---|---|---|
| link标签 | HTML解析阶段 | 可并行 | 入口样式、第三方库 |
| @import | 父CSS解析后 | 串行依赖 | 样式内部模块聚合 |
如果一个main.css用了五层@import嵌套,浏览器可能要往返多次才能拿到全部规则,首屏渲染会被明显拖慢。因此纯前端静态站点若流量敏感,应谨慎滥用@import;但在有打包工具的项目里,构建阶段会把@import内联合并,运行时其实不存在额外请求。
现代开发习惯是:源码阶段用@import做逻辑拆分提升可维护性,再通过Webpack、Vite等工具的CSS处理插件在打包时扁平化合并。这样既保留了“分文件编写”的清晰,又避免了“分文件请求”的损耗。
基于@import的模块化拆分实践
假设我们有一个后台管理系统,样式可以拆成如下结构:基础变量、混合宏、布局、组件、页面补丁。每个文件只关心自己的一块,修改按钮样式时不会误触布局代码。
/* core/variables.css */
:root {
--primary: #2b6cb0;
--radius: 4px;
}
/* components/button.css */
.btn {
background: var(--primary);
border-radius: var(--radius);
padding: 6px 12px;
}
/* main.css */
@import "./core/variables.css";
@import "./components/button.css";
这种写法让团队成员遵守“样式即模块”的约定。新功能只需新增一个模块文件,并在main.css顶部加一行@import,不必在巨型文件里翻找插入位置。对于没有构建系统的旧项目,也可以手动用脚本把多个文件按import顺序拼接,再上传合并后的版本。
需要提醒的是,@import的路径推荐使用相对路径且注意层级的清晰。如果项目后续迁移到支持原生CSS模块的系统,这种扁平的引用结构也更容易被工具识别和转换,不会造成大量重构成本。
常见误区与避坑建议
第一个误区是认为@import和link性能一样。如前所述,串行请求在弱网环境下差异巨大。第二个误区是在媒体查询里写大量@import,导致条件样式文件无法被预加载扫描器提前发现。
如果项目完全无构建步骤,且对首屏速度要求高,优先用link拆分,或在服务端把CSS合并;@import更适合源码组织而非最终交付。
第三个误区是循环引用:A文件import B,B又import A,浏览器虽能容忍但维护者会陷入死循环式排查。拆分时应规定依赖方向,例如基础层不准依赖组件层,组件层可依赖基础层。
最后,记得在代码评审时检查@import是否写在文件顶端。很多编辑器格式化会把注释移到最前,若工具把普通规则提到了import之上,整个模块化就会静默失效。用lint规则约束位置,比靠人眼检查更稳妥。