CSS 样式方案

Next.js 支持一系列成熟的 CSS 方案:Tailwind CSSCSS Modules全局 CSS外部样式表SassCSS-in-JS。这一章重点讲前四种常用方式。

Tailwind CSS(推荐)

create-next-app 默认就帮你装好了 Tailwind。手动安装也很简单:

npm install -D tailwindcss @tailwindcss/postcss

postcss.config.mjs 启用:

export default {
  plugins: {
    '@tailwindcss/postcss': {},
  },
};

在全局 CSS 里导入:

/* app/globals.css */
@import 'tailwindcss';

在根布局里导入 CSS:

import './globals.css';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="zh-CN">
      <body>{children}</body>
    </html>
  );
}

接下来,随手写工具类:

export default function Page() {
  return (
    <main className="flex min-h-screen flex-col items-center justify-between p-24">
      <h1 className="text-4xl font-bold">欢迎使用 Next.js!</h1>
    </main>
  );
}

CSS Modules

适合组件级定制样式,避免全局类名冲突。文件命名为 *.module.css

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

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

Next.js 会生成唯一类名,跨文件同名也不会冲突。

全局 CSS

用在真正全局的样式上(比如 Tailwind 基础层、reset):

/* 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="zh-CN">
      <body>{children}</body>
    </html>
  );
}

提示:导航时,全局样式不会自动被卸载,可能彼此叠加造成冲突。建议只放「真正全局」的样式。

外部样式表

第三方包的 CSS 可以在 app 目录里任意位置 import:

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

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="zh-CN">
      <body className="container">{children}</body>
    </html>
  );
}

排序与合并

生产构建时 Next.js 会合并并代码分割 CSS。CSS 的最终顺序取决于你的 import 顺序。

例如:

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

顺序是 base-button.module.csspage.module.css

实践建议:

  • CSS import 集中在单一入口文件。
  • 全局样式、Tailwind 入口都放在应用根部。
  • 大多数样式用 Tailwind,组件私有样式用 CSS Modules,极少用全局 CSS。
  • 禁用 sort-imports 之类自动排序 import 的 lint 规则,以免影响 CSS 顺序。
  • 开发和构建下 CSS 顺序可能略有差异,务必通过 next build 验证。

开发与生产

  • next dev 下 CSS 热更新,秒级反馈。
  • next build 把所有 CSS 压缩、拆包,路由只加载所需的最小集合。
  • 生产禁用 JS 仍能加载 CSS;开发下需要 JS 才能 Fast Refresh。

CSS 樣式方案

Next.js 支援多種成熟的 CSS 方案:Tailwind CSSCSS Modules全域 CSS外部樣式表SassCSS-in-JS。本章聚焦前四種常用做法。

Tailwind CSS(建議)

create-next-app 預設已安裝 Tailwind。若手動安裝:

npm install -D tailwindcss @tailwindcss/postcss

postcss.config.mjs 啟用:

export default {
  plugins: {
    '@tailwindcss/postcss': {},
  },
};

在全域 CSS 中匯入:

/* app/globals.css */
@import 'tailwindcss';

在根佈局中匯入 CSS:

import './globals.css';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="zh-HK">
      <body>{children}</body>
    </html>
  );
}

接著即可直接使用工具類:

export default function Page() {
  return (
    <main className="flex min-h-screen flex-col items-center justify-between p-24">
      <h1 className="text-4xl font-bold">歡迎使用 Next.js!</h1>
    </main>
  );
}

CSS Modules

適合元件層級自訂樣式,避免全域類名衝突。檔名以 *.module.css 結尾:

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

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

Next.js 會生成唯一類名,跨檔案同名不會衝突。

全域 CSS

用於真正全域的樣式(如 Tailwind 基礎層、reset):

/* 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="zh-HK">
      <body>{children}</body>
    </html>
  );
}

提示:導航時全域樣式不會自動卸載,彼此可能疊加造成衝突。僅放「真正全域」的樣式。

外部樣式表

第三方套件的 CSS 可在 app 目錄任意位置 import:

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

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="zh-HK">
      <body className="container">{children}</body>
    </html>
  );
}

排序與合併

生產建置時 Next.js 會合併並程式碼分割 CSS。最終順序依 import 順序而定。

例如:

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

順序為 base-button.module.csspage.module.css

實務建議:

  • CSS import 集中於單一入口檔。
  • 全域樣式、Tailwind 入口都放在應用根部。
  • 多數樣式使用 Tailwind,元件私有樣式使用 CSS Modules,極少使用全域 CSS。
  • 關閉 sort-imports 類自動排序 import 的 lint 規則,避免影響 CSS 順序。
  • 開發與建置下 CSS 順序可能略有不同,務必透過 next build 驗證。

開發與生產

  • next dev 下 CSS 熱更新,秒級回饋。
  • next build 會壓縮並拆分 CSS,路由僅載入所需最小集合。
  • 生產即使禁用 JS 也可載入 CSS;開發則需 JS 以支援 Fast Refresh。

CSS Styling

Next.js supports a broad lineup of CSS options: Tailwind CSS, CSS Modules, global CSS, external stylesheets, Sass, and CSS-in-JS. This chapter focuses on the four most common choices.

Tailwind CSS (recommended)

create-next-app already installs Tailwind for you. For a manual setup:

npm install -D tailwindcss @tailwindcss/postcss

Enable the PostCSS plugin in postcss.config.mjs:

export default {
  plugins: {
    '@tailwindcss/postcss': {},
  },
};

Import Tailwind from your global stylesheet:

/* app/globals.css */
@import 'tailwindcss';

Import the stylesheet from the root layout:

import './globals.css';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>{children}</body>
    </html>
  );
}

Now compose utility classes directly in your components:

export default function Page() {
  return (
    <main className="flex min-h-screen flex-col items-center justify-between p-24">
      <h1 className="text-4xl font-bold">Welcome to Next.js!</h1>
    </main>
  );
}

CSS Modules

Great for component-scoped styles that avoid class-name collisions. Name files *.module.css:

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

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

Next.js generates unique class names so the same selector in different files won't clash.

Global CSS

Use it for genuinely global styles (Tailwind's base layer, resets, etc.):

/* 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>
  );
}

Heads up: on navigation, global stylesheets aren't unmounted automatically, which can lead to subtle conflicts. Keep "global" for styles that really are global.

External stylesheets

Third-party CSS can be imported anywhere inside 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>
  );
}

Ordering and merging

In production, Next.js chunks and merges your CSS. Final order depends on the order of import statements:

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

Here the order is base-button.module.csspage.module.css.

Practical rules of thumb:

  • Keep CSS imports in a single entry file per area.
  • Import Tailwind and global stylesheets at the root.
  • Use Tailwind for most styling, CSS Modules for component-specific needs, and global CSS sparingly.
  • Disable auto-sort lint rules like sort-imports so they don't shuffle CSS order.
  • Dev and build can differ; always verify with next build.

Development vs production

  • next dev hot-reloads CSS for instant feedback.
  • next build minifies and chunks CSS so each route loads the minimum set.
  • CSS still loads with JS disabled in production; dev needs JS for Fast Refresh.