Menu

CSS

Next.js 支持多种处理 CSS 的方式,包括:

CSS Modules

Next.js 内置支持使用 .module.css 扩展名的 CSS Modules。

CSS Modules 通过自动创建唯一的类名来本地化 CSS 作用域。这允许你在不同文件中使用相同的类名而不必担心冲突。这种特性使 CSS Modules 成为包含组件级 CSS 的理想方式。

示例

CSS Modules 可以被导入到 app 目录中的任何文件:

app/dashboard/layout.tsx
TypeScript
import styles from './styles.module.css'
 
export default function DashboardLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return <section className={styles.dashboard}>{children}</section>
}
app/dashboard/styles.module.css
.dashboard {
  padding: 24px;
}

CSS Modules 仅对带有 .module.css.module.sass 扩展名的文件启用

在生产环境中,所有 CSS Module 文件将自动连接成多个经过代码分割的压缩 .css 文件。 这些 .css 文件代表了应用程序中的热执行路径,确保为应用程序加载最少量的 CSS 以进行渲染。

全局样式

全局样式可以导入到 app 目录中的任何布局、页面或组件中。

值得注意的是

  • 这与 pages 目录不同,在 pages 目录中你只能在 _app.js 文件中导入全局样式。
  • Next.js 不支持使用全局样式,除非它们确实是全局的,意味着它们可以应用于所有页面并在应用程序的整个生命周期中存在。这是因为 Next.js 使用 React 内置的样式表支持来与 Suspense 集成。这种内置支持目前不会在路由导航时移除样式表。因此,我们建议使用 CSS Modules 而不是全局样式。

例如,考虑一个名为 app/global.css 的样式表:

app/global.css
body {
  padding: 20px 20px 60px;
  max-width: 680px;
  margin: 0 auto;
}

在根布局(app/layout.js)中,导入 global.css 样式表以将样式应用到应用程序的每个路由:

app/layout.tsx
TypeScript
// 这些样式适用于应用程序中的每个路由
import './global.css'
 
export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
      <body>{children}</body>
    </html>
  )
}

外部样式表

由外部包发布的样式表可以在 app 目录中的任何位置导入,包括共置组件:

app/layout.tsx
TypeScript
import 'bootstrap/dist/css/bootstrap.css'
 
export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
      <body className="container">{children}</body>
    </html>
  )
}

值得注意的是:外部样式表必须直接从 npm 包导入或下载并与你的代码库共置。你不能使用 <link rel="stylesheet" />

排序和合并

Next.js 在生产构建过程中通过自动分块(合并)样式表来优化 CSS。CSS 的顺序_由你将样式表导入到应用程序代码中的顺序决定_。

例如,base-button.module.css 将在 page.module.css 之前排序,因为 <BaseButton><Page> 中首先被导入:

base-button.tsx
TypeScript
import styles from './base-button.module.css'
 
export function BaseButton() {
  return <button className={styles.primary} />
}
page.ts
TypeScript
import { BaseButton } from './base-button'
import styles from './page.module.css'
 
export default function Page() {
  return <BaseButton className={styles.primary} />
}

为了保持可预测的顺序,我们建议以下做法:

  • 只在单个 JS/TS 文件中导入一个 CSS 文件。
    • 如果使用全局类名,按照你希望它们应用的顺序在同一文件中导入全局样式。
  • 优先使用 CSS Modules 而非全局样式。
    • 为你的 CSS 模块使用一致的命名约定。例如,使用 <name>.module.css 而不是 <name>.tsx
  • 将共享样式提取到单独的共享组件中。
  • 如果使用 Tailwind,在文件顶部导入样式表,最好是在 Root Layout 中。
  • 关闭任何自动对导入进行排序的代码检查/格式化工具(例如 ESLint 的 sort-import)。这可能会无意中影响你的 CSS,因为 CSS 导入顺序_很重要_。

值得注意的是:

  • CSS 排序在开发模式下可能表现不同,始终确保检查构建(next build)以验证最终的 CSS 顺序。
  • 你可以使用 next.config.js 中的 cssChunking 选项来控制 CSS 如何分块。

其他功能

Next.js 包含额外功能以改善添加样式的创作体验:

  • 当使用 next dev 本地运行时,本地样式表(全局或 CSS 模块)将利用 Fast Refresh 在保存编辑时立即反映更改。
  • 当使用 next build 构建生产版本时,CSS 文件将被打包成更少的压缩 .css 文件,以减少获取样式所需的网络请求数量。
  • 如果你禁用 JavaScript,样式仍然会在生产构建(next start)中加载。但是,next dev 仍然需要 JavaScript 来启用 Fast Refresh