css modules 中 var(--x) 不生效的根本原因是 css 变量未真正注入全局作用域;必须将 :root 变量定义在禁用 modules 的独立 css 文件(如 tokens.css)中,并确保其在 .module.css 加载前被浏览器解析,才能被安全引用。

不能直接在 .module.css 里用 var(--color-primary) 引用外部定义在 :root 中的 CSS 变量——除非该变量确实已注入到全局作用域,且未被 CSS Modules 的构建流程隔离。
为什么 var(--x) 在 CSS Modules 里有时不生效
CSS Modules 本身不干涉 CSS 变量的运行时行为,但构建链路可能切断变量来源:
- 如果全局变量写在
globals.css里,而你只用@import './globals.css'引入,那它仍会被css-loader?modules当作模块处理,:root块里的--x会随文件局部化,无法被其他模块读取 - 如果变量定义在非 Modules 的 CSS 文件(如
main.css),但没通过style-loader或 HTML<link>显式注入到 DOM,浏览器根本看不到这些变量 -
postcss-modules-values这类插件只处理@value,和原生 CSS 变量--x完全无关,混用会导致误解
确保 :root 变量真正全局可用
必须让浏览器在解析任何 .module.css 前,就已加载并解析含 :root { --x: ... } 的样式。推荐做法:
- 把所有设计令牌统一写进一个非 Modules 的 CSS 文件,例如
src/styles/tokens.css,内容为::root { --color-primary: #007bff; --space-md: 0.75rem; } - 在 Webpack 配置中,对该文件禁用 Modules:
{ test: /tokens\.css$/, use: ['style-loader', 'css-loader'] }(注意没加?modules) - 或在 HTML 模板里用
<link rel="stylesheet" href="/tokens.css">静态引入 - Vue/Nuxt 等框架可配
css: ['@/styles/tokens.css'],Nuxt 会自动走非 Modules 流程
在 .module.css 中安全使用 var()
只要变量已在全局注册,模块内可直接引用,无需额外声明:
.button { background-color: var(--color-primary); padding: var(--space-md); }
但要注意:
- 不要在
:root外层、@import后或空选择器里写--x,否则无效 - 暗色模式切换需靠媒体查询或属性选择器覆盖,例如:
[data-theme="dark"] :root { --color-primary: #0d6efd; } - 避免循环引用:
--a: var(--b); --b: var(--a);会导致计算失败,值为initial - 未定义变量 fallback 写法:
color: var(--text-color, #333);,第二个参数仅当--text-color根本不存在时才生效
别试图用 :global() “导出” CSS 变量
:global() 只影响选择器作用域,对 :root 块或变量声明本身无意义。下面写法完全错误:
-
:global(:root) { --x: red; }→:root本就是全局,加:global多余且可能被解析异常 -
:global(--x) { }→ 语法非法,CSS 不支持这种写法
真正需要控制的是变量的**注入时机和位置**,不是“作用域修饰”。变量一旦在 :root 中声明并成功加载,所有后续 CSS(包括 Modules)都能访问——前提是它们运行在同一文档上下文里。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











