样式方案(上)
本教程共 42 篇 · 第 15 篇 · 更新于 2026-07-30 · 约 7 分钟阅读
15. 样式方案(上)
本节目标:了解 Next.js 支持的所有样式方案,理解 CSS Modules、全局 CSS 和 CSS-in-JS 的工作原理,学会在不同场景下选择合适的样式方案。
为什么样式方案这么多?
前端样式一直是令人头疼的问题。组件多了,类名容易冲突;样式大了,加载速度变慢。Next.js 作为全栈框架,提供了多种样式方案供你选择。
没有哪一种方案是绝对最好的。理解每种方案的特点,才能在实际项目中做出合理选择。
CSS Modules
CSS Modules 是 Next.js 内置支持的特性,它的核心思路是:局部作用域。
你可以用普通 CSS 写样式,但类名会被自动转换成唯一的标识符。这样,你在不同文件里写同名类名也不会冲突。
怎么用?
创建一个 .module.css 文件,然后在组件中引入:
/* app/blog/blog.module.css */
.blog {
padding: 24px;
max-width: 800px;
margin: 0 auto;
}
.title {
font-size: 2rem;
font-weight: bold;
}
// app/blog/page.tsx
import styles from './blog.module.css'
export default function Page() {
return (
<main className={styles.blog}>
<h1 className={styles.title}>我的博客</h1>
</main>
)
}
NoteCSS Modules 的类名在构建时会被自动转换为类似
blog_blog_x7k9a的唯一标识符,确保不会与其他文件的类名冲突。
适合什么场景?
CSS Modules 适合中大型项目。每个组件的样式独立管理,不用担心全局污染。团队成员并行开发时,也不会因为类名重复导致样式被覆盖。
全局 CSS
全局 CSS 是最传统的方式。你写一个 CSS 文件,在根布局中引入,样式就会应用到所有页面。
/* app/global.css */
body {
padding: 20px 20px 60px;
max-width: 680px;
margin: 0 auto;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
}
a {
color: #0070f3;
text-decoration: none;
}
// app/layout.tsx
import './global.css'
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="zh">
<body>{children}</body>
</html>
)
}
需要注意的地方
全局 CSS 可以引入到任意布局或组件中。但官方有个提醒:由于 Next.js 对样式表的处理方式,路由切换时样式表不会被移除,可能导致冲突。
Tip推荐做法:全局 CSS 只用于真正全局的样式(比如 CSS Reset、基础排版),组件级别的样式用 CSS Modules 或 Tailwind CSS。
外部样式表
你想用 Bootstrap、Ant Design 这些第三方库的 CSS?直接在组件里引入就行:
// app/layout.tsx
import 'bootstrap/dist/css/bootstrap.css'
export default function RootLayout({ children }) {
return (
<html lang="zh">
<body className="container">{children}</body>
</html>
)
}
从 React 19 开始,还可以用 <link> 标签引入样式表,这也是官方推荐的另一种方式。
CSS-in-JS
CSS-in-JS 是把 CSS 写在 JavaScript 里的方案。它让你可以动态生成样式,还能利用 JavaScript 变量。
Next.js 的 App Router 支持多种 CSS-in-JS 库,比如 styled-components、styled-jsx、vanilla-extract、stylex 等。
配置三步走
在 App Router 中使用 CSS-in-JS 需要三步:
- 创建一个样式注册表(Style Registry)
- 用
useServerInsertedHTML钩子注入样式 - 用注册表组件包裹你的应用
styled-components 示例
先在 next.config.ts 中启用:
// next.config.ts
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
compiler: {
styledComponents: true,
},
}
export default nextConfig
然后创建注册表组件:
// lib/registry.tsx
'use client'
import React, { useState } from 'react'
import { useServerInsertedHTML } from 'next/navigation'
import { ServerStyleSheet, StyleSheetManager } from 'styled-components'
export default function StyledComponentsRegistry({
children,
}: {
children: React.ReactNode
}) {
const [styledComponentsStyleSheet] = useState(() => new ServerStyleSheet())
useServerInsertedHTML(() => {
const styles = styledComponentsStyleSheet.getStyleElement()
styledComponentsStyleSheet.instance.clearTag()
return <>{styles}</>
})
if (typeof window !== 'undefined') return <>{children}</>
return (
<StyleSheetManager sheet={styledComponentsStyleSheet.instance}>
{children}
</StyleSheetManager>
)
}
最后在根布局中使用:
// app/layout.tsx
import StyledComponentsRegistry from './lib/registry'
export default function RootLayout({ children }) {
return (
<html lang="zh">
<body>
<StyledComponentsRegistry>{children}</StyledComponentsRegistry>
</body>
</html>
)
}
styled-jsx 示例
styled-jsx 是 Next.js 官方提供的 CSS-in-JS 方案,不需要额外配置:
export default function Card() {
return (
<div className="card">
<h2>标题</h2>
<p>内容</p>
<style jsx>{`
.card {
padding: 16px;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
h2 {
margin: 0 0 8px;
}
`}</style>
</div>
)
}
WarningCSS-in-JS 在 Server Components 和流式渲染中的支持要求库作者兼容 React 18+ 的新特性。使用前确认你的库版本是否支持。
样式合并与优先级
Next.js 在生产构建时会自动合并和压缩 CSS 文件。样式的最终顺序取决于你在代码中的引入顺序。
比如 BaseButton 组件先引入 base-button.module.css,然后页面引入 page.module.css,那么后者的样式优先级更高。
// page.tsx
import { BaseButton } from './base-button'
import styles from './page.module.css'
export default function Page() {
return <BaseButton className={styles.primary} />
}
推荐做法
想保持样式顺序可预测,记住几点:
- 把 CSS 限制在单一入口文件中引入
- 全局样式和 Tailwind 在根布局引入
- 大部分样式需求用 Tailwind CSS 的工具类
- Tailwind 不够用时,用 CSS Modules 补充组件样式
- 关闭 ESLint 的
sort-imports规则,避免自动排序打乱样式顺序
开发 vs 生产环境
在开发环境(next dev),CSS 修改会即时生效,配合 Fast Refresh 体验很好。
在生产环境(next build),所有 CSS 文件会被自动合并压缩成多个小型 .css 文件,确保每个路由只加载必要的样式。
Note开发环境中的 CSS 排序可能和生产环境不一致。上线前记得跑一次
next build验证最终效果。
方案对比总结
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| CSS Modules | 局部作用域、零运行时开销 | 类名不可读 | 中大型项目组件样式 |
| 全局 CSS | 简单直接 | 容易命名冲突 | 全局基础样式 |
| 外部样式表 | 直接用第三方库 | 可能有冗余 | Bootstrap/Ant Design 等 |
| CSS-in-JS | 动态样式、组件封装 | 运行时开销、配置复杂 | 需要动态主题的场景 |
下一节我们会深入 Tailwind CSS,这是目前 Next.js 官方推荐的样式方案。