如何在应用中使用 CSS

Next.js 提供了多种在应用中使用 CSS 的方式,包括:

CSS 模块 (CSS Modules)

CSS 模块通过生成唯一的类名来实现 CSS 的局部作用域,这样您可以在不同文件中使用相同的类名而无需担心命名冲突。

要开始使用 CSS 模块,请创建一个扩展名为 .module.css 的新文件,并将其导入到 app 目录中的任意组件:

app/blog/blog.module.css
.blog {
  padding: 24px;
}
import styles from './blog.module.css'

export default function Page() {
  return <main className={styles.blog}></main>
}
import styles from './blog.module.css'

export default function Layout() {
  return <main className={styles.blog}></main>
}

全局 CSS (Global CSS)

您可以使用全局 CSS 来为整个应用应用样式。

创建一个 app/global.css 文件并将其导入根布局 (root layout),这样样式将应用到应用中的每个路由

app/global.css
body {
  padding: 20px 20px 60px;
  max-width: 680px;
  margin: 0 auto;
}
// 这些样式将应用到应用中的每个路由
import './global.css'

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

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>{children}</body>
    </html>
  )
}

须知: 全局样式可以导入到 app 目录中的任何布局、页面或组件。但由于 Next.js 使用 React 内置的样式表支持来与 Suspense 集成,目前在不同路由之间导航时不会移除样式表,这可能导致冲突。我们建议将全局样式用于真正全局的 CSS,而对于局部作用域的 CSS 使用 CSS 模块 (CSS Modules)

外部样式表 (External Stylesheets)

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

import 'bootstrap/dist/css/bootstrap.css'

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

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body className="container">{children}</body>
    </html>
  )
}

须知: 在 React 19 中,也可以使用 <link rel="stylesheet" href="..." />。更多信息请参阅 React link 文档

排序与合并 (Ordering and Merging)

Next.js 在生产构建时会通过自动分块(合并)样式表来优化 CSS。CSS 的顺序取决于您在代码中导入样式的顺序

例如,base-button.module.css 会排在 page.module.css 之前,因为 <BaseButton>page.module.css 之前导入:

import { BaseButton } from './base-button'
import styles from './page.module.css'

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

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

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

export function BaseButton() {
  return <button className={styles.primary} />
}

推荐做法

为了保持 CSS 顺序的可预测性:

  • 尽量将 CSS 导入限制在单个 JavaScript 或 TypeScript 入口文件中
  • 在应用的根目录中导入全局样式和 Tailwind 样式表
  • 对于嵌套组件,使用 CSS 模块而非全局样式
  • 为 CSS 模块使用一致的命名约定。例如,使用 <name>.module.css 而非 <name>.tsx
  • 将共享样式提取到共享组件中以避免重复导入
  • 关闭自动排序导入的 linter 或格式化工具,如 ESLint 的 sort-imports
  • 您可以在 next.config.js 中使用 cssChunking 选项来控制 CSS 的分块方式

开发与生产环境 (Development vs Production)

  • 在开发环境 (next dev) 中,CSS 更新会通过 快速刷新 (Fast Refresh) 即时应用
  • 在生产环境 (next build) 中,所有 CSS 文件会自动合并为多个经过压缩和代码拆分.css 文件,确保为路由加载最少数量的 CSS
  • 在生产环境中,即使禁用 JavaScript,CSS 仍会加载,但在开发环境中需要 JavaScript 来实现快速刷新
  • CSS 顺序在开发环境中可能表现不同,请务必检查构建 (next build) 以验证最终的 CSS 顺序