es modules 原生不支持 import css,必须通过 link 标签、fetch + style 注入或构建工具(如 vite)转译实现;vite 中的 import './x.css' 是构建时语法糖,:export 仅在 css modules 下生效且为静态值。

ES Modules 不能直接 import CSS 文件
浏览器原生 import 不支持直接加载 .css 文件,写 import './style.css' 会报错:TypeError: Failed to resolve module specifier。这不是你路径写错了,是规范层面不支持——ESM 只认 JavaScript 模块。
真正能用 import 加载 CSS 的,只有构建工具(如 Vite、Webpack)或支持 CSS 模块化方案的运行时环境(比如某些 SSR 框架做了劫持)。纯浏览器 ESM 场景下,必须换思路。
- 用
link标签动态插入:适合按需加载、主题切换等场景 - 用构建工具转译:Vite 默认支持
import './style.css',但背后是把 CSS 提取为字符串再注入<style></style> - 若用原生 ESM 开发,CSS 必须走
fetch+document.createElement('style')手动注入
Vite 中的 CSS 模块导入其实是“假模块”
Vite 允许你写 import './module.css',但它不是在运行时解析 CSS,而是在构建阶段把该文件内容提取出来,拼进最终的 style 标签或单独的 .css 文件里。也就是说,它不提供 CSS 的“模块作用域”或“导出变量”,只是语法糖。
真正有模块语义的是 :export 语法(仅限 .module.css):
立即学习“前端免费学习笔记(深入)”;
/* theme.module.css */
.primary { color: blue; }
:export {
primaryColor: blue;
}然后 JS 中可以这样读:
import styles from './theme.module.css'; console.log(styles.primaryColor); // 'blue'
-
:export只在 Vite / Webpack 的 CSS Modules 模式下生效,普通.css文件无效 - 导出的值只能是字符串、数字或 CSS 变量名(不计算值),不能是表达式或函数
- 多个
:export块会被合并,但同名 key 会覆盖,没有警告
按模块导出 CSS 变量要靠 :export + 自定义属性
想让一个 CSS 文件“导出主题色”,不能只靠 :export,还得配合 CSS 自定义属性(--color-primary)才能被 JS 读取和复用。
推荐写法是双保险:
/* colors.module.css */
:root {
--color-primary: #007bff;
}
:export {
primary: #007bff;
primaryVar: '--color-primary';
}JS 中既可用 JS 变量,也能操作 CSS 变量:
import vars from './colors.module.css'; document.documentElement.style.setProperty(vars.primaryVar, vars.primary);
- 纯
:export导出的是编译时静态值,无法响应运行时变化 - 如果 CSS 变量依赖 JS 计算(比如暗色模式切换),必须用 JS 主动 setProperty,不能指望
:export动态更新 - Vite 开发时热更新对
:export支持不稳定,改了值可能需要手动刷新
动态引入 CSS 模块容易忽略加载时机
用 import() 动态加载 CSS(如 import('./admin.css'))看似方便,但实际返回的是一个 Promise,且多数构建工具返回的是空对象({}),不是样式内容本身。
这意味着你不能靠 await import('./xxx.css') 来判断样式是否就绪;真正的加载完成,得监听 link.onload 或检查 document.styleSheets。
- 动态
importCSS 在 Vite 中返回{ default: undefined },别试图解构它 - 想确认样式已生效,得用
getComputedStyle查某个元素的 computed style,而不是看 Promise 是否 resolve - 多个动态 CSS 并发加载时,顺序不保证,若存在依赖(如重置样式在前、组件样式在后),需手动控制加载链
CSS 的模块化不是语言特性,而是构建与约定的混合产物。最易被忽略的一点:你写的每个 :export、每个 import './x.css',背后都依赖具体工具链的行为,换一套构建配置,行为可能完全不同。










