根本原因是CSS Modules未将类名映射到DOM:硬编码字符串类名(如"btn")与哈希化真实类名(如Button_btn__abc123)不匹配;必须用import styles from './X.module.css'并以styles.btn访问,且文件后缀须为.module.css。

样式丢失不是CSS写错了,而是类名根本没挂到DOM上,或挂了但浏览器找不到对应规则——这是CSS Modules环境下最典型的失联现象。
检查JSX中是否用了硬编码类名
React/Vue里写className="btn primary"或:class="'btn primary'",在启用CSS Modules的项目中等于白写。模块化后真实类名类似Button_btn__abc123,而字符串"btn"不会被自动映射。
- 必须通过
import styles from './Button.module.css'导入对象,再用styles.btn取值 - 文件后缀必须是
.module.css(或.module.scss等),否则构建工具不触发模块逻辑 - 动态拼接时别混用:
{`${styles.btn} ${isPrimary ? 'primary' : ''}`}是错的;应写成{`${styles.btn} ${isPrimary ? styles.primary : ''}`}
确认第三方组件样式是否被跳过处理
像antd、element-plus这类库的CSS文件默认放在node_modules里,Webpack/Vite会直接跳过css-loader的modules配置,导致它们以全局方式加载——但你的业务组件又依赖局部作用域,结果就是DOM上有ant-btn,Computed里却没样式。
- 不要在
.module.css里用:global(.ant-btn)试图覆盖——它只能加一条规则,无法还原整套布局/间距/状态样式 - 正确做法:单独建一个
src/index.css,在里面@import 'antd/dist/reset.css',并确保这个文件不带.module后缀 - Vite用户需检查
css.modules.generateScopedName是否误匹配了node_modules路径,必要时加exclude: /node_modules/
排查浮层类组件(Modal/Tooltip)的挂载点问题
即使CSS加载正确,Modal、Tooltip等组件默认渲染到document.body,完全脱离你组件的DOM树,CSS Modules或<style scoped>根本触达不到。
立即学习“前端免费学习笔记(深入)”;
- React中必须传
getPopupContainer={() => document.getElementById('app')},把浮层塞进你的根容器 - Vue中要用
<teleport to=".my-root">,并在外层容器上加class="my-root" - 别只改
prefixCls——它不改变选择器权重,也不解决挂载位置导致的作用域断裂
留意热更新(HMR)下的哈希不一致
开发时改一个.module.css,页面上可能同时存在Button_btn__a1b2c和Button_btn__x9y8z两个类名,部分按钮生效、部分失效——这不是bug,是Webpack开发模式下哈希基于模块路径而非内容生成所致。
- 生产构建用
contenthash,哈希稳定;开发时这种“双类名共存”属正常现象 - 不要在HMR期间手动清空
document.styleSheets或重载CSS link,会加剧混乱 - 若需精确控制,可临时将
localIdentName设为[name]__[local]--[hash:base64:3]缩短哈希长度,便于肉眼比对
真正棘手的从来不是“样式没写对”,而是“样式根本没走对路”——类名映射、构建路径、挂载上下文、运行时环境,四者只要断一环,就只剩干瞪眼。


















