next.js 中只有 .module.scss 文件才能启用 css modules 实现样式隔离,因构建系统仅识别该后缀并自动哈希类名;非 module 后缀或服务端组件中导入均会导致全局污染或报错。

Next.js 中使用 .module.scss 是防止样式污染最直接有效的方式——它不是“支持 SCSS”,而是“启用 CSS Modules 机制 + 支持 SCSS 语法”的组合行为,关键在文件名和导入位置。
为什么 Button.scss 不能防污染,但 Button.module.scss 可以
Next.js 的构建系统只对带 .module. 前缀的 CSS/SCSS/Less 文件自动启用 CSS Modules。没有这个前缀,哪怕内容写得再模块化,也会被当作全局样式处理:
-
Button.scss→ 构建时走普通 CSS 处理流程 → 类名不哈希 → 全局注入 → 与其他.button冲突 -
Button.module.scss→ 构建时识别为模块 → 自动启用modules: true→ 类名转成Button_button__abc123→ 仅限本组件作用域
不需要额外配置 Webpack 或 Vite,Next.js 开箱即用,前提是后缀必须是 .module.scss(或 .module.css、.module.less)。
import styles from './Button.module.scss' 必须在 Client Component 中
在 Next.js App Router 下,Server Component 里执行 import 会直接报错:Module not found: Can't resolve './Button.module.scss'。这不是路径问题,而是构建阶段跳过了服务端的样式解析:
- 必须在组件顶部加
"use client"声明 - 不能在
app/layout.tsx、app/page.tsx等服务端文件中 import 样式文件 - 如果用了
React.lazy或动态导入,确保目标组件也是 Client Component
SCSS 嵌套、变量、@import 在 .module.scss 中怎么用
SCSS 语法完全可用,但要注意模块边界:
- 嵌套选择器(如
.button { &:hover { ... } })会被正常编译,生成的类名仍保持局部性 - 全局变量(如
$primary-color: #007bff)可定义在单独的_variables.module.scss中,然后用@import引入 —— 注意:被 import 的文件也必须是.module.scss后缀,否则变量可能失效或污染全局 -
:global(.reset) { ... }可以显式脱离模块约束,但要慎用;:local(.icon)不必要,因为默认就是局部 - 不要在
.module.scss里写html、body或第三方库选择器(如.ant-btn),它们不会被模块化,且容易被覆盖
常见报错与对应检查点
样式没生效?控制台空 className?先看这几个地方:
-
styles.button是undefined→ 检查 CSS 文件中是否写了.button,JS 中是否写成styles.button(不能写styles.button-container,连字符会转驼峰) - 报错
Cannot find module './Button.module.scss'→ 路径没错的话,大概率是组件没加"use client" - 样式生效但类名没哈希(如 DOM 中显示
class="button")→ 文件名不是.module.scss,可能是.scss或.module.sass(Next.js 不识别后者) - 多个组件引入同一个
_mixins.module.scss却报重复定义 → 把 mixin 抽到_mixins.scss(无 module),只在需要的地方@import,避免被模块化
真正容易被忽略的是:SCSS 的功能(嵌套、变量)和 CSS Modules 的隔离机制是正交的——前者管写法便利,后者管作用域安全,二者靠 .module.scss 这个命名契约绑定。漏掉任何一个环节,污染就回来了。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











