必须将文件命名为.module.css(如Button.module.css)并用import styles from './X.module.css'导入,否则CSS Modules不生效;错误命名或导入方式会导致样式退化为全局、类名无哈希、className为空。

文件名必须是 .module.css 才生效
React 官方脚手架(如 Create React App、Vite)默认只对匹配 /\.module\.css$/ 的文件启用 CSS Modules。写成 Button.css 或 Button.modules.css 都不行,构建工具会直接跳过模块化处理,结果还是全局样式。
常见错误现象:样式没生效、类名没哈希、DevTools 里看到原始类名(比如 button 而不是 Button_button__abc123)——八成是文件后缀错了。
- ✅ 正确命名:
Button.module.css、Header.module.scss(如果配置了 sass-loader) - ❌ 错误命名:
Button.css、Button.mod.css、Button.Module.css(大小写敏感,Linux/macOS 下不识别) - 注意:重命名后,旧的
import './Button.css'会报模块未找到错误,必须同步更新 import 语句
import styles from './X.module.css' 是唯一合法导入方式
不能用 import './X.module.css',也不能用 import styles from './X.css'。前者不会注入任何类名对象,后者根本不会触发模块化逻辑。
导入后得到的是一个普通 JS 对象,键是原始类名,值是编译后的哈希类名。它不是字符串,也不是 DOM API,不能拼接、不能动态计算键名。
立即学习“前端免费学习笔记(深入)”;
- ✅ 正确用法:
className={styles.button} - ❌ 错误用法:
className="button"(绕过 modules,退化为全局) - ❌ 错误用法:
className={styles['btn-' + type]}(TS 编译通过但运行时为undefined,且无警告) - 需要条件组合?用
clsx:className={clsx(styles.button, props.primary && styles.primary)}
为什么 className={styles.xxx} 有时返回 undefined
这不是构建失败,而是引用链断了。CSS Modules 不报错,安静地返回 undefined,所以元素最终渲染出空 className="",样式消失。
排查顺序建议:
- 检查文件是否真叫
Button.module.css(不是button.module.css—— macOS/Linux 下路径大小写敏感) - 检查 import 路径是否和文件位置完全一致(比如组件在
src/components/Button,CSS 就得在同目录下,且 import 写import styles from './Button.module.css') - 检查 CSS 文件里写的类名是否和 JS 中访问的一致(比如 CSS 里是
.disabled,JS 却写了styles.disable)
全局样式和局部样式可以共存,但不能混写
import './base.css' 和 import styles from './Button.module.css' 完全兼容,因为它们走的是不同构建通道:前者注入全局样式表,后者生成带哈希的局部类名对象。
关键禁忌:不要在 .module.css 文件里 @import './base.css'。这会破坏模块边界,多数构建工具(如 CRA 默认配置)根本不支持这种写法,会导致构建失败或样式泄漏。
分工建议:
-
base.css:放:root变量、* { margin: 0 }、工具类(如.sr-only) -
Button.module.css:只放 Button 组件内部结构样式,比如.button、.icon
真正容易被忽略的是:模块文件一旦写错后缀或导入方式,就彻底退化为普通 CSS,而你可能几天都发现不了——因为页面看起来“好像也正常”。只有当多人协作、组件复用、CI 构建出现样式错乱时,才暴露问题。


















