Frontend Design System v3.1 — React + shadcn/ui + Tailwind CSS 统一视觉与实现规范,面向 AI Agent 的前端开发标准
Find a file
2026-07-17 21:51:17 +08:00
README.md refactor: 合并补充章节到主线,27章→20章,内容零删减 2026-07-17 21:51:17 +08:00

Frontend Design System v3.1

适用于所有前端项目的统一视觉与实现规范。
技术栈React + TypeScript + shadcn/ui + Tailwind CSS + Vite / Next.js
最后更新2026-07-17
设计哲学:亮色优先 · 信息密集 · 操作克制 · 胶水代码优先


、最高红线原则Agent 必须遵守)

  1. 禁止手搓基础交互组件。任何按钮、输入框、下拉、表格、弹窗、侧边栏、分页、开关、日期选择等,必须使用 shadcn/ui 组件(或本规范明确批准的扩展)。
  2. 只写胶水代码:组合已有组件 + 传 props + 处理事件 + 对接业务逻辑。禁止从零实现交互行为。
  3. 所有尺寸、颜色、圆角、字重、间距必须来自本规范定义的 Token,禁止魔法数字。
  4. 亮色为默认主题,必须同时支持暗色,通过 class="dark" 切换。
  5. 高度统一所有中号表单控件Button、Input、Select、Trigger默认高度必须为 36pxh-9)。
  6. 文字溢出必须处理标题、表格单元格、Badge 默认 truncate
  7. 移动端可点击区域 ≥ 44×44px
  8. 违反以上任一条,视为未遵循设计系统。

一、设计哲学

亮色优先、信息密集、操作克制、低视觉噪音。

  • 目标用户:运维 / 开发 / 业务人员,长时间盯屏,需要快速扫读关键信息。
  • 灵感来源Linear、Vercel Dashboard、Railway、shadcn/ui 官方示例。
  • 原则:
    • 用颜色传递状态,不用装饰分散注意力。
    • 卡片默认无阴影,仅 hover 时出现轻微强调。
    • 圆角、间距、字重严格遵循 8px 网格与本规范阶梯。
    • 优先复用,绝不重复造轮子。

二、技术栈(强制)

层级 选型 说明
框架 React 18/19 + TypeScript 函数组件 + Hooks
构建 Vite 或 Next.js (App Router) 新项目优先 Vite纯前端或 Next.js需 SSR
UI 组件 shadcn/ui 复制进项目的源码,禁止再封装黑盒
样式 Tailwind CSS v4 + CSS Variables 所有样式通过 Tailwind 工具类 + 变量
图标 lucide-react 统一使用,禁止 emoji、禁止其他图标库
状态 Zustand 或 React Context按需 简单项目可用 useState
路由 React Router 或 Next.js 内置
表单 react-hook-form + zod + shadcn Form 强制
表格 shadcn Data Table基于 TanStack Table 强制
主题 next-themes 或自实现 class 切换 支持 system / light / dark

安装与初始化要求

# 使用官方 CLI 初始化(必须)
npx shadcn@latest init

# 常用组件按需添加(禁止自己写)
npx shadcn@latest add button input select dropdown-menu dialog sheet card table form badge avatar separator tabs tooltip popover command checkbox switch radio-group label textarea calendar popover date-picker sonner

所有 shadcn 组件必须放在 src/components/ui/,业务组合组件放在 src/components/common/src/components/layout/


三、CSS 变量与颜色系统

所有颜色通过 CSS 变量定义,放在 src/index.css(或 globals.css)中。
shadcn 默认使用 HSL本规范保持兼容并扩展语义色。

3.1 亮色主题(默认)

:root {
  --background: 210 40% 98%;          /* #f8fafc */
  --foreground: 222 47% 11%;          /* #0f172a */
  --card: 0 0% 100%;                  /* #ffffff */
  --card-foreground: 222 47% 11%;
  --popover: 0 0% 100%;
  --popover-foreground: 222 47% 11%;
  --primary: 217 91% 60%;             /* #3b82f6 */
  --primary-foreground: 0 0% 100%;
  --secondary: 210 40% 96%;           /* #f1f5f9 */
  --secondary-foreground: 222 47% 11%;
  --muted: 210 40% 96%;
  --muted-foreground: 215 16% 47%;    /* #475569 */
  --accent: 210 40% 96%;
  --accent-foreground: 222 47% 11%;
  --destructive: 0 84% 60%;           /* #dc2626 */
  --destructive-foreground: 0 0% 100%;
  --border: 214 32% 91%;              /* #e2e8f0 */
  --input: 214 32% 91%;
  --ring: 217 91% 60%;
  --radius: 0.5rem;                   /* 8px 基础 */

  /* 扩展语义色 */
  --success: 142 76% 36%;             /* #16a34a */
  --success-foreground: 0 0% 100%;
  --warning: 32 95% 44%;              /* #d97706 */
  --warning-foreground: 0 0% 100%;
  --info: 199 89% 48%;                /* #0891b2 */
  --purple: 271 81% 56%;              /* #9333ea */

  /* 背景层级 */
  --bg: 210 40% 98%;
  --bg-2: 210 40% 96%;
  --bg-3: 214 32% 91%;

  /* 文字层级 */
  --text: 222 47% 11%;
  --text-2: 215 16% 47%;
  --text-3: 215 20% 65%;              /* #94a3b8 */

  /* Header */
  --header-bg: 0 0% 100% / 0.88;
}

3.2 暗色主题

.dark {
  --background: 224 28% 7%;           /* #0f1117 */
  --foreground: 210 20% 92%;          /* #e4e6ed */
  --card: 224 22% 12%;                /* #1e2230 */
  --card-foreground: 210 20% 92%;
  --popover: 224 22% 12%;
  --popover-foreground: 210 20% 92%;
  --primary: 217 91% 60%;
  --primary-foreground: 0 0% 100%;
  --secondary: 224 20% 16%;
  --secondary-foreground: 210 20% 92%;
  --muted: 224 20% 16%;
  --muted-foreground: 215 14% 55%;    /* #8b8fa3 */
  --accent: 224 20% 16%;
  --accent-foreground: 210 20% 92%;
  --destructive: 0 72% 51%;
  --destructive-foreground: 0 0% 100%;
  --border: 224 16% 20%;              /* #2a2e3d */
  --input: 224 16% 20%;
  --ring: 217 91% 60%;

  --success: 142 71% 45%;
  --warning: 38 92% 50%;
  --info: 189 94% 43%;
  --purple: 270 91% 65%;

  --bg: 224 28% 7%;
  --bg-2: 224 22% 12%;
  --bg-3: 224 18% 16%;

  --text: 210 20% 92%;
  --text-2: 215 14% 55%;
  --text-3: 220 10% 40%;

  --header-bg: 224 22% 12% / 0.92;
}

3.3 色彩使用规则

场景 用法
主操作 / 链接 bg-primary text-primary-foreground
成功 / 在线 text-successbg-success/10 text-success
错误 / 危险 text-destructivebg-destructive/10 text-destructive
警告 text-warningbg-warning/10 text-warning
次要文字 text-muted-foreground
半透明标签底 bg-xxx/10bg-xxx/15(禁止纯色背景)
进度条轨道 bg-muted
遮罩 bg-black/60 + backdrop-blur-sm

3.4 数据可视化(图表)配色与样式

当项目使用图表库Recharts、Chart.js、ECharts、Tremor 等)时,必须遵守以下规范。

3.4.1 分类色板(按顺序使用)

export const chartColors = [
  "hsl(217 91% 60%)",   // primary 蓝
  "hsl(142 76% 36%)",   // success 绿
  "hsl(32 95% 44%)",    // warning 橙
  "hsl(271 81% 56%)",   // purple
  "hsl(199 89% 48%)",   // cyan / info
  "hsl(0 84% 60%)",     // destructive 红
  "hsl(215 16% 47%)",   // muted
]

暗色模式下使用同一组 HSL亮度已在语义色中适配。

3.4.2 强制样式

元素 规范
背景 透明或 hsl(var(--card))
网格线 hsl(var(--border)),线宽 1px虚线可选
坐标轴文字 text-[11px] fill-muted-foreground
Tooltip 使用 shadcn 风格:bg-popover border border-border rounded-lg shadow-md text-[12px]
图例 字号 12px颜色 text-muted-foreground
线宽(折线) 2px
点半径 34px
动画 可开启,时长 ≤ 500ms

3.4.3 禁止

  • 禁止使用图表库默认的彩虹色
  • 禁止硬编码 #3b82f6 等,必须引用上述色板或 CSS 变量
  • 禁止在暗色模式下仍使用浅色网格导致看不清

四、字体系统

4.1 字体栈

font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;

/* 等宽 */
font-family: "SF Mono", "Menlo", "Consolas", "Liberation Mono", monospace;

tailwind.config 中:

fontFamily: {
  sans: ['-apple-system', 'BlinkMacSystemFont', '"SF Pro Display"', '"Segoe UI"', 'Roboto', 'sans-serif'],
  mono: ['"SF Mono"', 'Menlo', 'Consolas', 'monospace'],
}

4.2 字号与字重阶梯(强制)

用途 类名 / 尺寸 字重 其他
Logo / 页面大标题 text-base font-bold (16px) 700 whitespace-nowrap
卡片大数值 text-xl font-bold tracking-tight (20px) 700 letter-spacing: -0.5px
卡片标题 / Section 标题 text-[15px] font-bold 700
正文 / 按钮文字 text-[13px] font-medium 500/600 主要正文尺寸
次要信息 / Header 信息 text-xs font-semibold (12px) 600
Section 小标题 text-xs font-bold uppercase tracking-wider 700 letter-spacing: 1px
Badge / 状态标签 text-[11px] font-bold uppercase tracking-wide 700
极小标注 text-[10px] font-bold uppercase 700
代码 / 日志 text-xs font-mono 400 leading-relaxed

字重规则

  • 700所有标题、数值、Badge、主按钮文字
  • 600次要按钮、Header 信息
  • 500正文描述
  • 400仅长文本与代码块

4.3 行高

  • 正文:leading-normalleading-relaxed1.5
  • 标题 / 数值:leading-noneleading-tight
  • 表格单元格:leading-none

4.4 移动端

@media (max-width: 768px) {
  /* 正文不小于 14px */
  body { font-size: 14px; }
  /* input 防 iOS 缩放 */
  input, select, textarea { font-size: 16px !important; }
}

五、圆角系统

元素 圆角 Tailwind
按钮 / 输入框 / Select 8px rounded-md(对应 --radius
卡片 14px rounded-xl
大容器 / Section 16px rounded-2xl
Dialog / Sheet 18px rounded-[18px]
Badge / 胶囊按钮 9999px rounded-full
代码块 / 日志区 12px rounded-lg
进度条 3px rounded-[3px]
状态圆点 50% rounded-full
Logo 色块 7px rounded-[7px]

规则:圆角随元素尺寸正相关。控制类组件统一 rounded-md


六、间距系统8px 基准)

场景 间距 Tailwind
页面左右内边距 24px px-6
Header 高度 52px h-[52px]
Section 垂直间距 24px space-y-6 / gap-6
Grid 卡片间距 14px gap-3.5
卡片内边距 1618px p-4px-[18px] py-4
表单行间距 16px space-y-4
按钮组间距 8px gap-2
图标与文字间距 68px gap-1.5 / gap-2
Section 标题下方 12px mb-3
Dialog 内边距 28px p-7

禁止使用非 4 的倍数间距(除 14px 卡片 gap 外)。


七、阴影、边框与层级

7.1 阴影与边框

  • 边框:统一 border border-border1px solid
  • 卡片默认无阴影
  • 卡片 hover
    className="... transition-all hover:shadow-[0_0_0_1px_hsl(var(--primary)),0_6px_24px_rgba(59,130,246,0.1)]"
    
  • 浮层Dropdown / Popovershadow-md
  • Dialogshadow-lg
  • Header:无阴影,使用 border-b border-border

7.2 Z-Index 层级表(强制)

所有项目必须使用以下层级,禁止随意写 z-50z-9999 等魔法数字。

层级 z-index 用途
基础内容 auto / 0 页面正常流
粘性表头 / 局部悬浮 10 表格 sticky header
Header 50 顶部导航
Sidebar展开遮罩 40 移动端侧边栏遮罩
Dropdown / Popover / Select 60 下拉与气泡
Tooltip 70 提示
Dialog / Sheet 遮罩 80 模态遮罩
Dialog / Sheet 内容 90 模态内容
Toast 100 消息提示(最高)

在 Tailwind 中推荐扩展:

// tailwind preset
zIndex: {
  sticky: "10",
  header: "50",
  dropdown: "60",
  tooltip: "70",
  modal: "80",
  modalContent: "90",
  toast: "100",
}

使用时写 z-headerz-dropdown 等,禁止硬编码数字。


八、图标系统

8.1 强制规则

  • 只使用 lucide-react
  • 禁止 emoji、禁止 FontAwesome、禁止其他图标库
  • 统一 strokeWidth={1.8}(或 2
  • 尺寸通过 class 控制

8.2 尺寸

场景 尺寸 类名
Section 标题旁 16×16 h-4 w-4
Header / 卡片内 14×14 h-3.5 w-3.5
按钮内 / 极小 12×12 h-3 w-3
大图标(空状态等) 24×24 h-6 w-6

8.3 颜色

  • 默认:text-muted-foreground
  • 可交互:text-foreground
  • 强调:跟随父级 text-primary / text-destructive

8.4 常用图标映射(必须统一)

用途 图标名
设置 Settings
搜索 Search
刷新 RefreshCw
关闭 X
成功 Check / CheckCircle2
警告 AlertTriangle
错误 XCircle
信息 Info
时间 Clock
终端 / 日志 Terminal
复制 Copy
亮色 Sun
暗色 Moon
菜单 Menu
服务器 Server
CPU Cpu
存储 HardDrive
用户 User
退出 LogOut
加号 Plus
更多 MoreHorizontal
编辑 Pencil
删除 Trash2
外部链接 ExternalLink
侧边栏折叠 PanelLeftClose / PanelLeftOpen

九、组件规范核心Agent 必须严格遵守)

9.1 按钮Button

必须使用 import { Button } from "@/components/ui/button"

变体与用途

变体 用途 类名补充
default 主操作
secondary 次要操作
outline 边框按钮
ghost 文字/图标按钮、取消
destructive 删除 / 危险
link 链接样式

尺寸(强制)

size 高度 类名 使用场景
sm 28px (h-7) size="sm" 表格内操作、紧凑区
默认 36px (h-9) 不写或 size="default" 几乎所有场景
lg 40px (h-10) size="lg" 页面级主 CTA
icon 36×36 size="icon" 纯图标按钮

强制样式覆盖(在 button.tsx 中统一)

// 默认高度必须是 h-9 (36px)
default: "h-9 px-4 py-2",
sm: "h-7 rounded-md px-3 text-xs",
lg: "h-10 rounded-md px-8",
icon: "h-9 w-9",
  • 字重:font-semibold600
  • 圆角:rounded-md
  • 图标与文字间距:gap-1.5gap-2
  • active 态:轻微 scale-[0.97](可选,在全局加)

禁止

  • 禁止自定义 height / h-[xxpx]
  • 禁止使用原生 <button> 而不包 Button 组件
  • 禁止主按钮使用非 primary 色

9.2 输入框Input

必须使用 import { Input } from "@/components/ui/input"

  • 高度:强制 h-936px
  • 圆角:rounded-md
  • 字号:text-sm1314px
  • 边框:border-input
  • focusring-2 ring-ring ring-offset-2
  • 禁止高度与 Button 不一致

9.3 选择器Select

必须使用 shadcn Select 系列组件。

  • Trigger 高度:强制 h-9
  • 与 Input、Button 完全对齐
  • 禁止自己写下拉菜单

9.4 卡片Card

必须使用 import { Card, CardHeader, CardTitle, CardContent, CardFooter } from "@/components/ui/card"

<Card className="rounded-xl border bg-card shadow-none transition-all hover:shadow-[0_0_0_1px_hsl(var(--primary)),0_6px_24px_rgba(59,130,246,0.1)]">
  <CardHeader className="p-4 pb-2">
    <CardTitle className="text-[15px] font-bold">标题</CardTitle>
  </CardHeader>
  <CardContent className="p-4 pt-0">
    ...
  </CardContent>
</Card>
  • 默认无阴影
  • 内边距 1618px
  • 圆角 rounded-xl14px

9.5 表格Data Table

必须使用 shadcn Data Table基于 @tanstack/react-table)。

  • 表头:text-xs font-semibold uppercase tracking-wider text-muted-foreground
  • 行高:最小 44px方便点击
  • 单元格文字默认 truncate
  • 操作列固定右侧
  • 移动端(<640px表格容器加 overflow-x-auto

禁止手写 <table> 实现业务表格。

9.6 Badge / 状态标签

import { Badge } from "@/components/ui/badge"

// 语义变体
<Badge variant="default">默认</Badge>
<Badge className="bg-success/10 text-success border-transparent">成功</Badge>
<Badge className="bg-destructive/10 text-destructive border-transparent">错误</Badge>
<Badge className="bg-warning/10 text-warning border-transparent">警告</Badge>
  • 圆角:rounded-full
  • 字号:text-[11px] font-bold uppercase
  • 内边距:px-2.5 py-0.5

9.7 状态圆点

<span className="inline-block h-1.5 w-1.5 rounded-full bg-success" />  // 在线
<span className="inline-block h-1.5 w-1.5 rounded-full bg-destructive" /> // 离线
<span className="inline-block h-1.5 w-1.5 rounded-full bg-warning" />   // 警告
<span className="inline-block h-1.5 w-1.5 rounded-full bg-muted-foreground" /> // 未知

9.8 Dialog / Sheet弹窗 / 抽屉)

  • Dialog居中宽度默认 sm:max-w-md,圆角 rounded-[18px],内边距 p-7
  • Sheet侧滑常用于移动端或详情
  • 遮罩:bg-black/60 backdrop-blur-sm
  • 禁止自己实现 Modal

9.9 Header顶部导航

高度52px
定位sticky top-0 z-50
背景bg-background/88 backdrop-blur-xl border-b
布局flex items-center justify-between px-6

左侧Logo26×26 圆角色块 + 文字) + 状态点
右侧:操作按钮组 + 主题切换

主题切换按钮使用 Button variant="ghost" size="icon" + Sun / Moon 图标。

9.10 Sidebar侧边栏

  • 宽度:展开 240px折叠 64px
  • 背景:bg-cardbg-background
  • 边框:border-r border-border
  • 菜单项高度3640px
  • 激活态:bg-accent text-accent-foreground 或左侧 2px primary 指示条
  • 图标 + 文字,折叠时只显示图标 + Tooltip
  • 必须使用可折叠实现(可基于 shadcn 社区 Sidebar 或自组合 Sheet + 导航)

9.11 表单

强制使用:

import { useForm } from "react-hook-form"
import { zodResolver } from "@hookform/resolvers/zod"
import { Form, FormField, FormItem, FormLabel, FormControl, FormMessage } from "@/components/ui/form"
  • Label 与控件间距:space-y-2
  • 错误提示:红色文字,位于控件下方
  • 桌面端 label 可固定宽度右对齐(可选)

9.12 其他强制组件

需求 必须使用
开关 Switch
复选 Checkbox
单选 RadioGroup
分页 自组合或社区 Pagination基于 shadcn
标签页 Tabs
提示 Tooltip
命令面板 Command
日期 Calendar + Popover
进度 Progress
骨架 Skeleton
分隔线 Separator
头像 Avatar

9.13 Toast / 消息提示

9.13.1 强制使用

使用 shadcn 推荐的 sonner@radix-ui/react-toast 封装(通过 npx shadcn add sonner)。

禁止自己写固定定位的 div 作为 Toast。

9.13.2 位置与行为

属性
位置 右下角(bottom-right
自动关闭 成功 / 信息 3s警告 / 错误 5s
最大同时显示 3 条
动画 从下方滑入 + 淡入200300ms

9.13.3 类型与样式

toast.success("操作成功")
toast.error("操作失败,请重试")
toast.warning("请注意…")
toast.info("提示信息")
toast.loading("处理中…")   // 可手动 dismiss
  • 左侧可保留 3px 语义色竖线(成功绿 / 错误红 / 警告橙)
  • 文字:text-[13px] font-medium
  • 圆角:rounded-lg12px
  • 阴影:shadow-lg

9.13.4 禁止

  • 禁止用 alert()
  • 禁止用 Dialog 模拟轻量提示
  • 禁止 Toast 覆盖重要操作按钮

9.14 自定义业务组合组件

shadcn 原生组件之外,以下组合组件必须按本规范实现(或直接使用共享包中的实现),禁止两个项目各自自由发挥

9.14.1 PageHeader页面标题区

// 必须包含:标题 + 可选描述 + 可选右侧操作区
interface PageHeaderProps {
  title: string
  description?: string
  actions?: React.ReactNode
}

// 结构强制
<div className="flex flex-col gap-1 sm:flex-row sm:items-center sm:justify-between mb-6">
  <div>
    <h1 className="text-base font-bold tracking-tight">{title}</h1>
    {description && (
      <p className="text-[13px] text-muted-foreground mt-1">{description}</p>
    )}
  </div>
  {actions && <div className="flex items-center gap-2 mt-3 sm:mt-0">{actions}</div>}
</div>
  • 标题字号:text-base font-bold16px
  • 描述:text-[13px] text-muted-foreground
  • 与下方内容间距:mb-624px

9.14.2 StatCard数据指标卡片

interface StatCardProps {
  label: string          // 小标题uppercase
  value: string | number // 大数值
  icon?: React.ReactNode
  trend?: { value: string; direction: "up" | "down" | "neutral" }
  className?: string
}

强制样式:

  • 使用 Card,圆角 rounded-xl,内边距 p-4px-[18px] py-4
  • labeltext-[11px] font-bold uppercase tracking-wider text-muted-foreground
  • valuetext-xl font-bold tracking-tight
  • 默认无阴影hover 使用本规范卡片 hover 效果
  • 图标放在右上角,h-4 w-4 text-muted-foreground

9.14.3 EmptyState空状态

interface EmptyStateProps {
  icon?: React.ReactNode     // 默认使用 Inbox 或 FileX
  title: string
  description?: string
  action?: React.ReactNode   // 通常是一个 Button
}

强制布局:

<div className="flex flex-col items-center justify-center py-16 px-6 text-center">
  <div className="h-12 w-12 rounded-full bg-muted flex items-center justify-center mb-4">
    {icon || <Inbox className="h-6 w-6 text-muted-foreground" />}
  </div>
  <h3 className="text-[15px] font-bold mb-1">{title}</h3>
  {description && (
    <p className="text-[13px] text-muted-foreground max-w-sm mb-6">{description}</p>
  )}
  {action}
</div>
  • 禁止只显示一行「暂无数据」文字
  • 图标容器必须是圆形 + bg-muted

9.14.4 PageLoading整页加载

<div className="flex items-center justify-center min-h-[400px]">
  <Loader2 className="h-8 w-8 animate-spin text-muted-foreground" />
</div>

或使用多个 Skeleton 按页面真实结构排列(推荐仪表盘场景)。

9.14.5 ErrorState错误 / 失败状态)

interface ErrorStateProps {
  title?: string          // 默认「加载失败」
  description?: string
  retry?: () => void
}
  • 图标使用 AlertTriangleXCircle,颜色 text-destructive
  • 提供「重试」按钮(variant="outline"
  • 布局与 EmptyState 保持一致的垂直居中结构

9.14.6 面包屑Breadcrumb

必须使用 shadcn Breadcrumb 组件。

  • 字号:text-[13px]
  • 当前页:font-medium text-foreground
  • 上级:text-muted-foreground hover:text-foreground
  • 分隔符使用 ChevronRighth-3.5 w-3.5

9.14.7 分页器Pagination

必须基于 shadcn 风格实现(或共享包提供)。

  • 按钮高度:h-9(与规范控件一致)
  • 当前页:variant="outline"bg-primary text-primary-foreground
  • 移动端可只显示「上一页 / 下一页 + 页码信息」

9.14.8 业务组件放置位置

src/components/common/
├── PageHeader.tsx
├── StatCard.tsx
├── EmptyState.tsx
├── ErrorState.tsx
├── PageLoading.tsx
└── ...

两个项目应尽量使用共享包中的同一实现;若暂时无法共享,则必须按本规范像素级一致实现。

9.15 加载态 / 空状态 / 错误态统一模式

场景 必须使用的模式 禁止
首次加载整页 PageLoading 或结构化 Skeleton 白屏、无提示
区块加载 对应区域 Skeleton 整个页面转圈
列表 / 表格无数据 EmptyState 只显示「暂无数据」一行字
接口报错 ErrorState + 重试按钮 静默失败、只 console.error
按钮提交中 Button disabled + Loader2 图标旋转 可重复点击
表格刷新 表头或右上角小 Spinner保留旧数据 清空表格再转圈

Skeleton 颜色必须使用 bg-muted,圆角与真实组件一致。


十、布局系统

10.1 页面结构

<div className="min-h-screen bg-background text-foreground">
  <Header />
  <div className="flex">
    <Sidebar />
    <main className="flex-1 p-6 overflow-auto">
      {/* 内容 */}
    </main>
  </div>
</div>

10.2 Grid

// 4 列
<div className="grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-4 gap-3.5">

// 2 列
<div className="grid grid-cols-1 md:grid-cols-2 gap-3.5">

断点:

  • < 640px1 列
  • 6401280px2 列
  • ≥ 1280px4 列

10.3 内容最大宽度(可选)

工具类页面可不限制;文档/设置页可加 max-w-5xl mx-auto


十一、主题切换

必须支持 light / dark / system。

推荐使用 next-themesNext.js或自实现

// 切换时给 <html> 添加/移除 class="dark"
document.documentElement.classList.toggle("dark")

切换按钮放在 Header 右侧,使用 Sun / Moon 图标,Button variant="ghost" size="icon"

初始化时读取 localStorageprefers-color-scheme


十二、移动端适配

强制规则

  • 所有可点击元素最小 44×44pxmin-h-11 min-w-11
  • 正文字号 ≥ 14px
  • Input / Select 在移动端 text-base16px防止 iOS 缩放
  • 底部安全区:pb-safepb-[env(safe-area-inset-bottom)]
  • 表格横向滚动
  • Header 可换行或变成抽屉菜单
  • Sheet 优先于 Dialog移动端

断点参考

sm: 640px
md: 768px
lg: 1024px
xl: 1280px

十三、动画与过渡

元素 属性 时长
按钮 hover/active all 150ms
卡片 hover all 200250ms
Dialog / Sheet data-state 动画 200300ms
页面切换 避免过度动画

原则:短、克制、即时反馈。禁止花哨动画。


十四、文字溢出处理(强制)

// 单行截断
className="truncate"

// 多行截断2 行)
className="line-clamp-2"

// 数字 / Badge / 状态永不换行
className="whitespace-nowrap"
  • 卡片标题、表格单元格、Header 信息、侧边栏菜单文字:默认 truncate
  • 长代码 / 日志:break-all + 横向滚动

十五、项目结构(推荐)

src/
├── components/
│   ├── ui/                 # shadcn 原始组件(只通过 CLI 添加)
│   ├── common/             # 业务通用组合组件BadgeStatus、PageHeader 等)
│   └── layout/             # Header、Sidebar、AppShell
├── hooks/                  # 自定义 hooks
├── lib/                    # utils.tscn 函数等)
├── styles/
│   └── globals.css         # CSS 变量 + Tailwind 指令
├── pages/ 或 app/          # 路由页面
├── stores/                 # Zustand
└── types/

十六、Agent 开发 Checklist每页必须自检

16.1 核心检查

  • 是否全部使用 shadcn/ui 组件?有无手搓 Button/Input/Select/Table/Modal
  • 所有中号控件高度是否为 36pxh-9
  • 按钮与输入框并排时高度是否完全一致?
  • 颜色是否全部来自 CSS 变量 / Tailwind token
  • 标题、表格单元格是否处理了 truncate
  • 暗色模式是否正常?
  • 移动端可点击区域是否 ≥ 44px
  • Input 在移动端是否 ≥ 16px
  • 图标是否全部来自 lucide-react
  • 是否存在魔法数字(随意 px 值)?
  • 卡片是否默认无阴影,仅 hover 强调?
  • 表单是否使用 react-hook-form + zod + shadcn Form

16.2 扩展检查

  • CSS 变量与 Tailwind preset 是否来自共享源(而非本地抄写)?
  • PageHeader / StatCard / EmptyState / ErrorState 是否按 §9.14 实现?
  • Toast 是否使用 sonner或统一封装位置与时长是否符合规范
  • 空数据是否使用 EmptyState 而不是一行文字?
  • z-index 是否只使用规范中的层级 token§7.2
  • components/ui 是否与另一项目同源(共享包或同一基准版本)?
  • 图表颜色是否使用 §3.4 色板?

十七、反模式(明确禁止)

  1. 自己写 <button><input><select><table> 实现业务交互
  2. 按钮高度写成 32px / 34px / 40px 等非规范值
  3. 使用 emoji 作为图标
  4. 卡片默认加 shadow
  5. 文字溢出不处理直接撑破布局
  6. 硬编码颜色(#3b82f6red 等)
  7. 在业务组件里大量写自定义 CSS 覆盖 shadcn 样式
  8. 移动端忽略触摸目标与安全区
  9. 不支持暗色模式
  10. 引入除 lucide-react 外的图标库

十八、版本历史

版本 日期 变更
v1.0 2026-06-12 原 NaiveUI 规范(暗色优先)
v2.0 2026-07-04 亮色优先 + NaiveUI 完善
v3.0 2026-07-17 全面转向 React + shadcn/ui + Tailwind强化胶水代码与 AI 可执行细节
v3.1 2026-07-17 合并补充章节图表配色、Z-Index、业务组合组件、Toast、状态模式、自检清单新增物理同步与版本锁定

十九、物理同步机制(强制跨项目一致)

两个(或多个)独立项目必须在视觉 Token 与基础 UI 源码层面物理同源,禁止「各自照文档抄写」。

19.1 推荐方案(二选一)

方案 适用场景 说明
A. 私有 npm 包(推荐) 项目已使用 monorepo 或有私有源 发布 @yourorg/design-tokens + @yourorg/ui
B. Git Submodule / 子仓库 快速落地、暂不发 npm 两个项目共同引用同一 design-system 仓库

19.2 必须共享的内容

@yourorg/design-tokens          # 或 submodule 中的 packages/tokens
├── src/
│   ├── css-variables.css       # 完整 :root 与 .dark 变量(本规范 §3
│   ├── tailwind-preset.ts      # fontFamily、borderRadius、colors 映射
│   └── index.ts                # 导出
└── package.json

@yourorg/ui                     # 可选但强烈推荐
├── src/
│   ├── components/ui/          # 锁定版本的 shadcn 组件源码
│   └── components/common/      # 本规范定义的业务组合组件
└── package.json

19.3 强制规则

  1. CSS 变量与 Tailwind preset 只允许存在一份源文件,两个项目必须 import 同一份,禁止在业务仓库内再维护一份副本。
  2. 修改 Token 后必须同时发版 / 更新 submodule并在两个项目中同步升级。
  3. 业务项目中的 globals.css 只允许:
    @import "@yourorg/design-tokens/css-variables.css";
    @tailwind base;
    @tailwind components;
    @tailwind utilities;
    
  4. 禁止在业务项目中覆盖 --primary--radius、控制高度等核心变量。

二十、shadcn 组件版本锁定与共享

20.1 问题

shadcn 是「复制源码」模式,不同时间执行 npx shadcn add 可能得到不同实现,导致两个项目组件行为或 class 不一致。

20.2 强制措施

  1. 锁定 components.json 与 CLI 版本
    在项目根目录记录:

    // components.json 中注明
    {
      "aliases": { ... },
      "$schema": "https://ui.shadcn.com/schema.json",
      "style": "new-york",          // 或选定的 style两个项目必须相同
      "rsc": false,
      "tsx": true,
      "tailwind": { ... }
    }
    
  2. 推荐把 src/components/ui/ 纳入共享包@yourorg/ui

    • 新增组件时只在共享包中执行 shadcn add
    • 业务项目通过包引用,不再各自 npx shadcn add
  3. 若暂时无法共享 UI 包

    • 建立一个「基准日期」或「基准 commit」
    • 两个项目的 components/ui 必须从同一 commit 复制
    • 后续升级必须同步进行,并记录在 changelog
  4. 禁止在业务项目中直接修改 components/ui 下的源码来「临时修样式」。样式差异必须通过 Tailwind 工具类或共享 Token 解决。


本规范是唯一真相来源。
Agent 在生成任何前端代码前,必须完整阅读并严格遵守以上所有条款。
有疑问时,优先选择「使用已有 shadcn 组件 + 本规范 Token」而不是自己创造。