本节摘要:Next.js 支持多种样式方案。本节讲清最常用的三种:Tailwind CSS(原子类)、CSS Modules(局部作用域)、全局样式,以及暗色主题与 CSS 变量的组织方式,并给出"哪种场景用哪种"的选型建议。
阅读完本节,你应当能够:
样式方案之争(Tailwind vs CSS Modules vs styled-components)是前端老话题。对 Next.js 来说,官方默认方案是 Tailwind,但不同团队习惯不同。核心问题不是"哪个最好",而是"哪种与你的项目节奏最匹配"。
直觉类比:样式方案像"写作工具"——Tailwind 是"模板化的公文格式"(约定清晰、写得快但限制格式),CSS Modules 是"自由写作"(想怎么写怎么写但要自己管),全局 CSS 是"统一排版规范"(一次性定义全站风格)。
💡 关键直觉:Next.js 的 CSS 生态兼容性很好——Tailwind、CSS Modules、Sass、styled-components 都能用。选择标准是团队熟悉度与项目类型,不是"框架支持哪个"。
create-next-app 默认集成 Tailwind。用原子类直接在 JSX 里写样式:
export default function Card() { return ( <div className="rounded-lg border border-gray-200 p-6 shadow-sm hover:shadow-md transition"> <h2 className="text-xl font-bold text-gray-900">标题</h2> <p className="mt-2 text-sm text-gray-600">内容</p> </div> ); }
Tailwind 的取舍:
文件名 xxx.module.css,类名自动加哈希,只作用于当前组件:
// components/Profile.module.css .card { border-radius: 8px; padding: 24px; } .title { font-size: 20px; font-weight: 700; } // components/Profile.tsx import styles from "./Profile.module.css"; export default function Profile() { return ( <div className={styles.card}> <h2 className={styles.title}>用户资料</h2> </div> ); }
取舍:传统 CSS 语法、天然隔离;但每组件一个文件,组织成本略高。
app/globals.css 定义全局基础(CSS 变量、reset、通用类):
/* app/globals.css */ :root { --color-primary: #2563eb; --color-bg: #ffffff; --color-text: #1f2937; } body { background: var(--color-bg); color: var(--color-text); font-family: system-ui, sans-serif; }
在根布局引入:import "./globals.css";
/* globals.css:主题变量 */ :root { --color-bg: #ffffff; --color-text: #1f2937; --color-card: #f9fafb; } .dark { --color-bg: #111827; --color-text: #f9fafb; --color-card: #1f2937; }
"use client"; import { useEffect, useState } from "react"; export function ThemeToggle() { const [dark, setDark] = useState(false); useEffect(() => { document.documentElement.classList.toggle("dark", dark); }, [dark]); return ( <button onClick={() => setDark(!dark)}> {dark ? "浅色" : "暗色"} </button> ); }
说明:更完善的方案用 next-themes(支持系统偏好、无闪烁),此处演示原理。
Tailwind 的 dark 变体配合 class 策略:
// tailwind.config.ts export default { darkMode: "class", // 用 class 控制暗色 // ... };
<div className="bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100"> 自动适配主题 </div>
| 场景 | 方案 |
|---|---|
| 快速开发、团队统一 | Tailwind |
| 传统 CSS 习惯、组件库协作 | CSS Modules |
| 全站主题变量、基础样式 | globals.css + CSS 变量 |
| 复杂动画、动态样式 | styled-components / CSS-in-JS |
实践组合:globals.css(变量与 reset)+ Tailwind(日常开发)+ 少量 CSS Modules(复杂组件)。
| 误区 | 现象 | 正解 |
|---|---|---|
| 全局样式互相污染 | 类名冲突 | 用 CSS Modules 或 Tailwind |
| Tailwind 类不生效 | 忘了配置文件/未引入 | 确认 tailwind.config 的 content 路径 |
| 暗色模式闪白 | 主题切换晚于首屏 | 用 next-themes 或内联脚本 |
| CSS 变量在客户端无效 | 变量定义位置不对 | 定义在 :root 或 html 上 |
| 样式在 SSR 中丢失 | 水合不一致 | CSS-in-JS 需配合框架配置 |
// components/ThemeCard.tsx import styles from "./ThemeCard.module.css"; export default function ThemeCard({ title, children, }: { title: string; children: React.ReactNode; }) { return ( <div className={styles.card}> <h3 className={styles.title}>{title}</h3> {children} </div> ); }
/* components/ThemeCard.module.css */ .card { border: 1px solid var(--color-border, #e5e7eb); border-radius: 12px; padding: 24px; background: var(--color-card, #fff); transition: background 0.2s; } .title { font-size: 18px; font-weight: 600; margin-bottom: 12px; }
组件用 CSS Modules 管理自己的样式,主题用全局 CSS 变量切换——局部样式与全局主题分离,是 Next.js 样式组织的推荐形态。
为什么推荐"全局变量 + 局部样式"的组合:全局 CSS 变量管"主题"(颜色、间距、字体——全站统一),局部样式管"组件"(某个按钮、卡片的细节)。主题变化(暗色模式)时只需切换变量,组件样式自动跟随,不需要逐个组件改。
一句话:样式方案的关键不是"选哪个",而是"主题统一、局部隔离、性能可控"——三个原则对齐了,工具都是好工具。
问:Tailwind 和 CSS Modules 能一起用吗?
能。Tailwind 处理通用样式(布局、间距、颜色),CSS Modules 处理复杂组件(伪元素、媒体查询、嵌套)。两者共存没有冲突。
问:暗色模式如何避免刷新闪白?
闪白是因为 CSS 变量在 JS 执行后才切换。方案:next-themes(服务端注入内联脚本,首屏前设置主题)或手动在根布局内联一段脚本读取 localStorage 设置 class。
问:全局样式会影响所有页面吗?
会。globals.css 里的选择器作用于所有页面。所以全局样式只放"基础"(变量、reset、通用类),具体组件样式用局部方案。
问:怎么知道 Tailwind 类有没有生效?
常见原因:未重启 dev、类名拼写错误、被更高优先级样式覆盖。用浏览器开发者工具检查元素的计算样式即可定位。
样式方案没有"最好的",只有"适合团队的"——Tailwind 快、CSS Modules 稳、全局变量管主题。推荐组合:globals.css 定义变量与 reset,Tailwind 做主开发,CSS Modules 处理复杂组件,暗色模式用 class 策略。记住目标:主题统一、局部隔离、性能可控。
做一个主题切换器来验证本节知识:在 globals.css 里用 CSS 变量定义两套主题(浅色/暗色),写一个 ThemeToggle 客户端组件切换 html 的 class,用 localStorage 记住用户选择,刷新后保持。再做一个组件分别用 Tailwind 与 CSS Modules 实现相同样式,对比两种方案的写代码体验。
进阶练习:用 next-themes 重构主题切换(解决刷新闪白),并给组件库页面(按钮、卡片、输入框)配上暗色样式——通过 class 策略让 Tailwind 的 dark: 变体自动适配。做完后,主题体系就完整了。