CSS Modules通过构建时重命名类名为带路径和哈希的唯一标识(如components_Button__button___aBc2d)从物理层面消除冲突;必须显式配置localIdentName为path__[local]___[hash:base64:5],并确保文件后缀、路径大小写及导入方式正确。

因为 CSS Modules 在构建阶段就把 .button 这类原始类名,替换成带路径和哈希的唯一标识(如 components_Button__button___aBc2d),冲突不是被“避免”,而是从物理层面被消除。
类名生成发生在构建时,不依赖 JS 执行
CSS Modules 的重命名动作由 css-loader 或 postcss-modules 在打包过程中完成,跟组件是否渲染、JS 是否加载、服务端还是客户端完全无关。这意味着:
- SSR 和 CSR 渲染出的 class 名字必然一致,不存在 FOUC 或 hydrate 失败导致样式错乱
- 静态 HTML 预览或 JS 报错时,样式仍能通过 class 属性生效(不像 CSS-in-JS 会直接裸奔)
- 热更新(HMR)不会残留旧样式规则,没有优先级错乱风险
哈希唯一性取决于路径 + 文件名 + 类名 + 内容
默认配置下冲突频发,是因为只用了 [name]__[local];真正防冲突必须显式配置 localIdentName:
- 推荐值:
[path][name]__[local]___[hash:base64:5]——[path]确保src/components/Button.module.css和src/pages/Button.module.css绝对隔离 -
[hash:base64:5]足够短便于调试,又足够唯一;别用:8或:md5,无必要且拖慢构建 - Umi4/Vite/Webpack 均适用该 pattern,但 Webpack 必须写在
css-loader.options.modules下,不能放顶层
失效的常见原因比想象中更隐蔽
看到 className={styles.button} 报 undefined,大概率不是代码写错了,而是构建环节没走通:
立即学习“前端免费学习笔记(深入)”;
- 文件后缀不是
.module.css(比如写成Button.css或Button.module.scss却没配好 Sass loader) - import 路径大小写不一致(
./button.module.cssvs./Button.module.css,尤其在 macOS/Linux 上敏感) - 在
dangerouslySetInnerHTML或字符串模板里硬写了class="button"—— 模块类名只存在于 JS 对象中,不会自动注入全局 -
@import './reset.css'进模块文件,导入的仍是全局 CSS,等价于写:global()
真正验证是否生效,只看浏览器开发者工具里 DOM 元素的 class 属性:出现含路径、双下划线、三段分隔、短哈希的类名(如 components_Header__title___aBc2d)才算成功;如果还是 header 或 header__title___12345(缺路径),说明配置没接管编译流程。


















