css modules 是一种构建时样式模块化方案,通过哈希重命名类名(如 .btn → .button_btn__abc123)实现组件级作用域隔离,避免全局污染;需经 webpack 等工具处理,必须 import styles from './x.module.css' 后用 styles.btn 引用。

CSS Modules 不是浏览器原生能力,它必须经过构建工具(如 Webpack)处理才能生效;没走构建流程直接用 .module.css 文件,样式会完全不工作。
为什么 import './Button.module.css' 后 class 名变了?
CSS Modules 的核心行为就是「自动作用域化」:所有 class 和 @keyframes 名称默认被哈希重命名,比如 btn 可能变成 Button_btn__abc123。这不是 bug,而是设计目标——避免全局污染。
- 重命名规则由构建配置决定,常见有
[name]_[local]__[hash:base64:5]这类 pattern - 如果你在 DevTools 里找不到原始 class 名,别慌,去 Elements 面板看实际渲染的 class 属性值
- 想保留某个 class 不被重命名?用
:global(.header)包裹,但应慎用,违背模块化初衷
如何在 JS 中正确使用 CSS Modules 的 class?
不能像传统 CSS 那样写死字符串 className="btn",必须从导入对象中取值。
- 写法必须是:
import styles from './Button.module.css';,然后className={styles.btn} - 多个 class 拼接用
clsx或模板字面量:className={`${styles.btn} ${styles.primary}`} - 如果用了 TypeScript,记得配
@types/css-modules,否则styles.xxx会报类型错误 - 动态 class 名(如
styles[theme])需要显式声明类型或用as const避免隐式 any
和普通 CSS、CSS-in-JS 相比,CSS Modules 的边界在哪?
它解决的是「组件级样式隔离」,不是「全链路样式方案」。容易高估它的能力:
- 不处理全局重置(
normalize.css)、主题变量(需配合:root或 CSS 自定义属性)、动画复用(@keyframes仍要手动导出) - 无法跨文件共享 class 逻辑(比如多个组件都要用
visually-hidden),得抽成单独的shared.module.css - 服务端渲染时,若未正确提取 CSS,可能造成 FOUC;构建产物中每个 module 对应一个独立 CSS 块,chunk 数量会上升
- 它和
scoped(Vue)或Shadow DOM不同:隔离靠命名,不靠 DOM 边界,父子组件间样式仍可穿透(除非父组件也用 Modules)
真正难的不是写 import styles from 'x.module.css',而是判断哪些样式该进 module、哪些该提成 design token、哪些该交给原子类工具(如 Tailwind)——这三者的混合使用,才是日常开发里最常卡壳的地方。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











