App Router中全局Sass必须在app/layout.tsx首行导入,如import './globals.scss',不可在页面、组件或useEffect中导入,否则报错;局部Sass需用.module.scss后缀启用CSS Modules。

App Router 中全局 Sass 文件必须放在 app/layout.tsx 顶层导入
全局 Sass(如 app/globals.scss)不能在页面、组件或 useEffect 里导入,否则构建报错:Global CSS cannot be imported from files other than your Custom _app.js——即使你用的是 App Router,Next.js 仍沿用这条校验逻辑。真正有效的唯一位置是 app/layout.tsx 的最顶部(第一行 import),且不能加 'use client'。
常见错误包括:
- 把
import './globals.scss'写在return后面、组件函数体内,或包裹在条件判断中 - 路径写成
../styles/globals.scss却没确认该路径相对于app/layout.tsx是否正确 - 误将
globals.scss放在pages/下,或混用 Pages Router 的_app.js—— App Router 下它完全被忽略
局部 Sass 文件要用 .module.scss 后缀才能启用作用域
Next.js 对 Sass 的局部支持依赖文件命名约定:只有以 .module.scss 结尾的文件才会被自动编译为 CSS Modules,生成哈希类名,避免样式污染。直接写 Button.scss 并导入,会被当作全局样式处理,导致类名冲突或构建警告。
使用方式很简单:
- 新建
app/components/Button.module.scss,写普通 Sass 规则(支持嵌套、变量、@mixin) - 在组件中
import styles from './Button.module.scss' - 用
className={styles.container}绑定,不是字符串字面量
注意:Sass 变量和 @mixin 在模块文件里可用,但不能跨文件共享——想复用需抽到 _variables.scss 并在每个 .module.scss 中 @use。
app/layout.tsx 导入 Sass 时不能含 @layer 以外的 PostCSS 特性
Next.js 默认不启用完整的 PostCSS 插件链来处理 app/ 下的全局 Sass。如果你在 globals.scss 里写了 @tailwind base,没问题;但若用了未配置的 @import url(...)、@custom-media 或自定义 PostCSS 插件语法,构建会失败或静默忽略。
安全做法是:
- 全局 Sass 文件只做重置、基础排版、工具类(如
.sr-only) - Tailwind 指令统一放在
app/globals.css,再由app/layout.tsx导入;Sass 专注业务样式逻辑 - 检查
postcss.config.mjs是否包含@tailwindcss/postcss,其他插件(如postcss-nested)需显式安装并配置,否则@nest无效
混用 Sass 和 CSS Modules 时,composes 不生效
Sass 的 @extend 和 CSS Modules 的 composes 机制互不兼容。你在 Button.module.scss 里写 composes: container from './Layout.module.css',Next.js 会报错或降级为普通 class 字符串拼接,失去作用域保护。
替代方案更可靠:
- 用 Sass 的
@include复用_mixins.scss中定义的样式块 - 把共用基础样式抽成独立的
.module.scss,然后在多个组件中分别@use并@include - 避免跨模块继承类名;CSS Modules 的设计哲学就是“不继承,只组合”
真正容易被忽略的一点:Sass 文件一旦被 app/layout.tsx 导入,就脱离了组件作用域,它的所有规则(包括嵌套选择器)都会全局生效——哪怕你只在 Sass 里写了 .button { &__icon { ... } },这个 .button__icon 仍可能意外覆盖其他组件的同名类。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











