现在做现代感强、美观的 Web 应用,Next.js 生态已经形成了一套事实标准的技术栈。本文详细介绍这套以 Next.js (App Router) 为核心的技术栈,每个库解决什么问题,以及它们如何配合。
技术栈全景
Next.js (App Router) ← 应用框架,路由/渲染/部署
├─ shadcn/ui ← 核心组件库(按钮、对话框等)
├─ Aceternity UI ← 动画与炫酷特效组件
│ 或 Magic UI
├─ Lucide Icons ← 图标
├─ next-themes ← 明暗主题切换
└─ next/font (Geist) ← 字体加载
核心思想:React + Tailwind CSS 打底,每个库只做一件事且做到极致,组合起来既现代又高效。
一、Next.js(App Router)—— 地基
Next.js 是整个技术栈的承载者。App Router(Next.js 13+ 引入)是它新的路由系统。
为什么选 App Router
| 特性 | 说明 |
|---|---|
| 文件系统路由 | app/about/page.tsx 自动对应 /about |
| Server Components | 默认在服务端渲染,减少客户端 JS |
| Streaming | 流式渲染,页面逐步加载 |
| 嵌套布局 | layout.tsx 共享布局,刷新不丢失 |
| 内置优化 | 图片、字体、脚本自动优化 |
Server vs Client Component
App Router 最核心的概念:
// 默认是 Server Component(服务端运行,不打包到客户端)
export default function Page() {
return <div>静态内容</div>
}
// 加 'use client' 变成 Client Component(客户端运行,可用 useState 等)
'use client'
import { useState } from 'react'
export default function Counter() {
const [n, setN] = useState(0)
return <button onClick={() => setN(n + 1)}>{n}</button>
}
默认服务端,需要交互时才标 `‘use client’ —— 这是性能的关键。
二、Tailwind CSS —— 样式基础
虽然你没直接提,但 shadcn/ui 和这些动画库都依赖 Tailwind,是这套技术栈的隐形地基。
// 传统 CSS
<button className="btn btn-primary">点击</button>
// Tailwind:原子化 class 直接写样式
<button className="bg-blue-500 hover:bg-blue-600 px-4 py-2 rounded-lg text-white">
点击
</button>
不用起类名、不用切换文件、样式即所见。配合 tailwind.config 的设计令牌(design tokens),整套应用的色彩、间距高度一致。
三、shadcn/ui —— 核心组件库
shadcn/ui 是这套栈的灵魂,它和传统组件库(Element UI、Ant Design)思路完全不同。
不是 npm 包,是代码生成器
传统组件库:npm install antd,然后 import { Button } from 'antd'。
shadcn/ui:把组件源码直接拷贝到你的项目里:
npx shadcn@latest init
npx shadcn@latest add button dialog card
之后 components/ui/button.tsx 这个文件就在你仓库里了,你可以随意改。
为什么这样设计
| 传统组件库 | shadcn/ui |
|---|---|
| 黑盒,样式难改 | 源码归你,随便改 |
| 全局样式覆盖,互相冲突 | 基于你自己的设计令牌 |
| 升级可能有 breaking change | 你的代码你做主 |
| 包体积大 | 按需添加,只用你要的 |
技术组成
- 基于 Radix UI(无样式的无障碍组件原语)
- 样式用 Tailwind
- 默认配合 next-themes 做暗色模式
import { Button } from "@/components/ui/button"
import {
Dialog, DialogContent, DialogTrigger
} from "@/components/ui/dialog"
<Dialog>
<DialogTrigger asChild>
<Button variant="outline">打开</Button>
</DialogTrigger>
<DialogContent>对话框内容</DialogContent>
</Dialog>
四、Aceternity UI / Magic UI —— 动画特效
shadcn/ui 负责实用的「按钮、表单、对话框」,而 Aceternity UI 和 Magic UI 负责炫酷的视觉特效:光晕、粒子、3D 卡片、文字渐变动画等。
Aceternity UI
特点:复制粘贴的开源动画组件,视觉冲击力强,常用于产品落地页、个人作品集。
- 鼠标跟随的光晕卡片(Spotlight)
- 滚动视差效果
- 文字逐字打字机效果
- 背景渐变流动(aurora)
Magic UI
特点:同样是复制粘贴的动画组件库,偏向细腻的微交互。
- 边框光效(Animated Beam)
- 数字滚动计数
- 文本动画(Text Animate)
- 骨架屏加载效果
怎么用
它们和 shadcn/ui 一样,不是 npm 安装,而是拷贝源码。比如 Aceternity 的 Spotlight 组件,拷贝过来后:
import { Spotlight } from "@/components/ui/spotlight"
export default function Hero() {
return (
<div className="relative">
<Spotlight className="-top-40 left-0" fill="white" />
<h1>炫酷的标题</h1>
</div>
)
}
底层依赖 Framer Motion(现在叫 Motion)做动画引擎。
五、Lucide Icons —— 图标
一个轻量、统一、可树摇的图标库,几千个图标,风格一致。
import { Home, Search, User } from "lucide-react"
<button>
<Home className="w-4 h-4" />
首页
</button>
| 特性 | 说明 |
|---|---|
| 风格统一 | 所有图标线条粗细一致 |
| 按需引入 | 只打包用到的图标 |
| 可定制 | className 直接控制大小、颜色 |
| shadcn/ui 默认图标 | 配合默契 |
六、next-themes —— 主题切换
实现明暗模式切换,且没有闪烁问题(FOUC,即刷新时先白屏闪一下再变暗)。
安装与配置
npm install next-themes
// app/layout.tsx
import { ThemeProvider } from "next-themes"
export default function RootLayout({ children }) {
return (
<html lang="zh" suppressHydrationWarning>
<body>
<ThemeProvider attribute="class" defaultTheme="system" enableSystem>
{children}
</ThemeProvider>
</body>
</html>
)
}
attribute="class":通过给<html>加class="dark"切换defaultTheme="system":跟随系统设置suppressHydrationWarning:必须加,避免服务端/客户端主题不一致的警告
切换按钮
"use client"
import { useTheme } from "next-themes"
import { Sun, Moon } from "lucide-react"
export function ThemeToggle() {
const { theme, setTheme } = useTheme()
return (
<Button onClick={() => setTheme(theme === "dark" ? "light" : "dark")}>
<Sun className="dark:hidden" />
<Moon className="hidden dark:block" />
</Button>
)
}
配合 Tailwind 的 dark: 前缀,所有组件自动适配暗色。
七、next/font + Geist —— 字体
next/font 的优势
传统字体加载用 <link> 引入 Google Fonts,有性能问题(额外请求、布局闪烁)。
next/font 在构建时把字体下载到本地:
- 零运行时网络请求
- 自动字体回退(FOUT 消除布局偏移)
- 自托管(隐私更好)
Geist 字体
Vercel 设计的字体,专为屏幕和代码优化,是现代 Web 应用的流行选择。
- Geist Sans:正文 UI 字体
- Geist Mono:等宽字体,用于代码、数字
// app/layout.tsx
import { Geist, Geist_Mono } from "geist/font/sans" // 或 next/font/google
const geistSans = Geist({ variable: "--font-geist-sans" })
const geistMono = Geist_Mono({ variable: "--font-geist-mono" })
export default function RootLayout({ children }) {
return (
<html className={`${geistSans.variable} ${geistMono.variable}`}>
<body>{children}</body>
</html>
)
}
然后在 Tailwind 配置里映射成 CSS 变量:
/* globals.css */
body {
font-family: var(--font-geist-sans);
}
code {
font-family: var(--font-geist-mono);
}
八、典型项目搭建流程
# 1. 创建 Next.js 项目(含 Tailwind)
npx create-next-app@latest my-app --typescript --tailwind --app
# 2. 初始化 shadcn/ui
cd my-app
npx shadcn@latest init
# 3. 按需添加组件
npx shadcn@latest add button card dialog dropdown-menu
# 4. 安装主题与图标
npm install next-themes lucide-react geist
# 5. 按需从 Aceternity / Magic UI 拷贝动画组件
九、为什么这套栈这么火
| 诉求 | 这套栈的解法 |
|---|---|
| 要好看现代 | shadcn/ui + Aceternity/Magic UI |
| 要性能 | Next.js SSR + Server Component |
| 要可定制 | 源码归你,不是黑盒 |
| 要类型安全 | 全 TypeScript |
| 要快速开发 | Tailwind + 复制粘贴组件 |
| 要无障碍 | Radix UI 底层保障 |
| 统一部署 | Vercel 一键发布 |
它的哲学是**「拥有你的代码」**:组件不是黑盒依赖,而是你仓库里可读、可改、可控的文件。这和传统「装包即用」的思路形成鲜明对比,也是它在开发者社区迅速流行的原因。
总结
这套技术栈的分工:
Next.js App Router → 框架与渲染
Tailwind CSS → 样式原子化
shadcn/ui → 实用组件(基于 Radix)
Aceternity/Magic → 视觉动画(基于 Framer Motion)
Lucide Icons → 图标
next-themes → 明暗模式
next/font + Geist → 字体
每个库都只做一件事,靠 React + Tailwind 这层公共底座组合起来。如果你的目标是做出既现代美观、又高性能、还完全可控的 Web 应用,这就是 2026 年最主流的选择。