28 KiB
前端样式设计规范 (STYLE_GUIDE)
版本:v2.0 — 规范化版本
文档性质变更说明:v1.0 由现有代码反向提炼而来,仅描述"现状",并列出大量"新旧并存 / 待统一"的问题清单。 v2.0 起,本文档是唯一权威规范:所有历史上并存的多套数值(多个品牌蓝、多个灰色、多套圆角体系等)已在本版本中收敛为唯一官方取值。
- 🟢 新代码 / 其他系统 / 新项目:必须(MUST)按本文档执行,禁止再引入本文档之外的颜色、字号、圆角、间距任意值。
- 🟡 存量 legacy 代码:允许暂时保留(不要求立即批量重构),但触碰到的每一处(改动、重构、修 bug)都必须顺手改为符合本规范的取值,禁止在旧代码基础上"抄一份"旧的任意值到新地方。
- 本指南不强制使用特定 UI 组件框架(React/Vue/Tailwind/Ant Design 等均可),只强制最终视觉呈现(色值、字号、圆角、阴影、间距、过渡时长/缓动)与本文档一致。不同技术栈的团队,请把本文档中的 CSS 变量按第 12 节的方法映射到自己的 token/主题系统。
0. 规范优先级说明
文档中出现的关键词含义(参考 RFC 2119 风格):
| 关键词 | 含义 |
|---|---|
| 必须 / 禁止 | 强制性规则,新代码不得违反,Code Review 应作为拒绝合并的理由 |
| 应当 | 强烈建议,没有特殊原因必须遵守;有正当理由例外时需在 PR 中说明 |
| 可以 | 允许的做法,非强制 |
1. 设计概览
项目整体风格是 浅色 + 深蓝侧栏 的 SaaS 控制台风格,所有新页面 / 新模块必须延续此基调:
- 基调色:极浅蓝灰背景
#f3f6f9,纯白卡片#ffffff,深蓝侧栏#09233f。 - 品牌主色:饱和中蓝
#1978d4(唯一官方品牌蓝,见 §2.7 废弃旧值列表)。 - 状态色:成功绿
#18b979/ 危险红#d75b5b(唯一官方危险色)/ 警告橙#e6a33c。 - 形状语言:统一采用
rounded-2xl / 3xl / 4xl圆角阶梯(4 / 6 / 8px 递增,见 §4.3),禁止新代码再使用任意像素圆角(如rounded-[7px])。 - 字体:Inter Variable(
/fonts/Inter-Variable.ttf,weight 100–900)+ PingFang SC / Microsoft YaHei / system-ui 中文回落。 - 阴影:
shadow-md(卡片)/shadow-xl(对话框/抽屉),禁止新增自定义阴影任意值。 - 动效:统一 100–200ms 过渡(抽屉类组件可到 450ms),弹层统一用
data-open/data-closed进出模式。
2. 色彩系统(唯一权威取值)
规则:任何新代码中出现的颜色,必须来自本节表格中的具名 token 或对应 CSS 变量 / Tailwind 语义类。禁止在新代码里直接写裸 hex 值,除非本节明确未覆盖的一次性边缘场景(且需在 PR 中说明原因)。
2.1 Token 定义位置
- 品牌 token:
frontend/app/app.css@theme { ... }块。 - 侧栏 token:
frontend/app/app.css@theme inline+:root { --sidebar-... }。 - shadcn 语义 token(
bg-primary/text-foreground等)实际值由@theme覆盖,UI 组件一律使用语义 token,不写 hex。
2.2 品牌色(Brand / Accent)
| 名称 | 十六进制 | CSS 变量 | 用途 |
|---|---|---|---|
| brand | #1978d4 |
--color-brand |
主色:CTA、链接、选中态、强调(对应 bg-primary/text-primary) |
| brand-strong | #0e5fb9 |
--color-brand-strong |
主色按下/激活 |
| brand-soft | #edf6ff |
--color-brand-soft |
主色浅底:标签背景、提示行 |
| brand-deep(新增) | #0e5bad |
--color-brand-deep |
渐变按钮的深色结束端(替代历史上散落的 #1268c9/#1175d8/#0e5bad 等值) |
渐变按钮官方写法(如仍需渐变视觉的按钮):linear-gradient(135deg, var(--color-brand), var(--color-brand-deep))。禁止再手写新的渐变端点色值。
2.3 状态色
| 名称 | 十六进制 | CSS 变量 | 用途 |
|---|---|---|---|
| success / success-strong / success-soft | #18b979 / #0f7d55 / #e8f7f1 |
--color-success* |
成功提示、确认按钮 |
| danger / danger-strong / danger-soft | #d75b5b / #a94f4f / #fff6f6 |
--color-danger* |
错误、删除、危险操作(对应 bg-destructive) |
| warning / warning-soft | #e6a33c / #fff0ee |
--color-warning* |
警示提示 |
2.4 中性文本 / 边框 / 背景
| 名称 | 十六进制 | CSS 变量 | 用途 |
|---|---|---|---|
| ink | #27394d |
--color-ink |
主要正文 |
| ink-muted | #5d7186 |
--color-ink-muted |
次要正文 |
| ink-subtle | #8b99a8 |
--color-ink-subtle |
辅助说明、占位 |
| ink-caption(新增) | #748598 |
--color-ink-caption |
表格表头/卡片小标签等"更淡一档"的说明文字(替代历史上 #748598/#758497/#8796a6/#8a9aaa 等近似灰色) |
| line | #dce4ec |
--color-line |
标准边框(对应 border-border),替代历史上 #dce5ed/#dfe7ef/#dfe6ed/#e7ecf1/#e8edf2/#e0e7ee 等近似边框色 |
| line-soft | #edf1f5 |
--color-line-soft |
表格行/分隔线 |
| bg | #f3f6f9 |
--color-bg |
页面背景 |
| bg-panel | #ffffff |
--color-bg-panel |
卡片/面板背景 |
| bg-canvas | #f9fbfd |
--color-bg-canvas |
画布背景 |
| bg-log | #17212b |
--color-bg-log |
日志/代码块深色背景 |
2.5 侧栏 token(独立主题)
| 名称 | 值 | 用途 |
|---|---|---|
--sidebar-background |
#09233f |
深蓝侧栏底 |
--sidebar-foreground |
#c9d7e7 |
侧栏默认文字 |
--sidebar-primary |
#1479e8 |
侧栏内强调主色 |
--sidebar-primary-foreground |
#ffffff |
主色文字 |
--sidebar-accent |
rgba(255,255,255,0.06) |
选中态背景 |
--sidebar-accent-foreground |
#ffffff |
选中态文字 |
--sidebar-border |
rgba(255,255,255,0.08) |
侧栏内分隔线 |
--sidebar-ring |
#5ca9ff |
focus ring |
规则:任何侧栏相关的自定义样式(如背景渐变)必须引用 var(--sidebar-background) 等变量,禁止再硬编码 #09233f。
2.6 shadcn 语义 token 映射
| Tailwind 类 | 对应变量 | 用途 |
|---|---|---|
bg-primary / text-primary / border-primary |
--color-brand |
主按钮、链接 |
bg-secondary |
浅灰 | 次级按钮 / 输入框默认态 |
bg-destructive / text-destructive |
--color-danger |
危险按钮 |
bg-muted / text-muted-foreground |
浅灰底 + --color-ink-muted |
次要容器、辅助文字 |
bg-popover / text-popover-foreground |
白底 | 浮层、菜单、对话框 |
bg-background / text-foreground |
页面背景 + --color-ink |
body、文本默认 |
bg-card / text-card-foreground |
卡片 | Card 容器 |
bg-input / border-input |
浅灰 | 输入框背景 |
border-border |
--color-line |
通用边框 |
border-ring / ring-ring |
浅蓝 | focus 边框 / 焦点环 |
border-destructive |
--color-danger |
错误状态边框 |
2.7 已废弃色值(禁止新代码使用)
以下 hex 曾在 legacy 页面中散落使用,新代码严禁再出现,一律替换为 §2.2–2.4 对应 token:
| 废弃值 | 替换为 |
|---|---|
#1881e7 / #126ac3 / #1268c9 / #1175d8 / #0e5bad / #1479e8(页面内联渐变)/ #2279c7 |
--color-brand / --color-brand-strong / --color-brand-deep(渐变见 §2.2) |
#e74c3c |
--color-danger(#d75b5b) |
#748598 / #758497 / #8796a6 / #8a9aaa |
--color-ink-caption(新代码首选)或 --color-ink-muted / --color-ink-subtle(视层级而定) |
#dce5ed / #dfe7ef / #dfe6ed / #e7ecf1 / #e8edf2 / #e0e7ee |
--color-line |
#81b2e7 |
--color-brand-soft 场景下配合使用,或改用 --color-brand 的透明度变体(如 text-primary/70),不再单独定义新 hex |
3. 字体系统
3.1 字体族
--font-sans: Inter, "PingFang SC", "Microsoft YaHei", system-ui, sans-serif;
字体文件:public/fonts/Inter-Variable.ttf(含 italic 变体),font-display: swap。
3.2 字号阶梯(唯一官方取值)
规则:新代码必须从下表取值,禁止再使用未定义的任意 text-[Npx]。
| Token / 类 | 像素 | 用途 |
|---|---|---|
text-4xs(新增 token) |
8px | badge / 角标(原 text-[8px]) |
text-3xs(新增 token) |
9px | 极小辅助文字(原 text-[9px]) |
text-2xs(新增 token) |
10px | 小标签 / 数字 / 计数(原 text-[10px],历史最高频) |
text-xs |
12px | 表头 / 小按钮 / 行内说明(统一原 text-[11px]/text-[12px]/text-[13px]) |
text-sm |
14px | 默认正文 / UI 组件默认字号 |
text-base |
16px | 强调正文 |
text-xl |
20px | 小标题 |
text-2xl+ |
24px+ | 大标题 / 特殊展示字号,按需在设计评审中确定 |
需要在
app.css的@theme中补充定义:--text-2xs: 0.625rem; /* 10px */ --text-3xs: 0.5625rem; /* 9px */ --text-4xs: 0.5rem; /* 8px */在此之前,可临时使用
text-[10px]等写法,但一旦 token 落地必须替换。
3.3 字重
| Token | 值 | 用途 |
|---|---|---|
font-medium |
500 | UI 组件默认(按钮/CardTitle/DialogTitle) |
font-medium-plus(新增 token) |
650 | Topbar / 主按钮等需要"比 medium 重、比 semibold 轻"的强调场景(原任意值 font-[650],现固化为官方 token,禁止再写 font-[650]) |
font-semibold |
600 | 强调文本 |
font-bold |
700 | 标题 |
font-extrabold |
800 | 大数字 / 品牌展示 |
需在
@theme中补充:--font-weight-medium-plus: 650;,并在 Tailwind 中暴露为font-medium-plus工具类。
3.4 行高 / 字间距
- 默认行高 1.5;对话框标题用
leading-none;长文本正文(如.notebook-md p)用line-height: 1.6。 - 字间距仅用于大写字母标签:
tracking-[0.08em]~tracking-[0.12em],禁止在正文中使用额外字间距。
4. 间距、圆角与布局
4.1 基础网格
Tailwind 默认 4px 网格(0.25rem),不自定义 --spacing 基数。
4.2 间距 Token(唯一官方取值)
规则:以下为新代码必须优先使用的语义间距 token,禁止再随手写 px-[22px] 这类任意值。
| Token(新增) | 值 | 用途(替代原任意值) |
|---|---|---|
--spacing-page-x |
22px | 页面左右内边距(原 px-[22px] / mx-[22px]) |
--spacing-button-x |
15px | 主按钮水平内边距(原 px-[15px]) |
--spacing-gap-icon |
7px | 按钮内图标间距(原 gap-[7px]) |
--spacing-gap-sm |
5px | 小行距(原 gap-[5px]) |
--spacing-gap-md |
9px | 列表/区块间距(原 gap-[9px] / gap-[10px] 就近取整为该 token 或 gap-2.5) |
其余场景优先使用 Tailwind 内建 token:p-2.5 / p-3 / p-4 / p-6 / gap-1.5 / gap-2 / gap-6 / px-3 / py-1。
4.3 圆角规范(唯一官方阶梯)
规则:新代码必须使用以下阶梯,禁止再引入新的任意像素圆角。历史任意值按下表强制迁移:
| 官方 Token | 像素 | 用途 | 替代的历史任意值 |
|---|---|---|---|
rounded(Tailwind 默认) |
4px | 极小元素(icon 容器等) | rounded-[4px] |
rounded-md |
6px | 小型控件、legacy 按钮/输入 | rounded-[5px] / rounded-[6px] / rounded-[7px] |
rounded-lg |
8px | 中等卡片/列表项 | rounded-[9px] / rounded-[10px] |
rounded-xl |
12px | 大号卡片、Tooltip | rounded-[11px] / rounded-[13px] |
rounded-2xl |
16px | Textarea / Skeleton | — |
rounded-3xl |
24px | Input / Combobox 弹出层 | — |
rounded-4xl |
32px | Button / Card / Dialog / Drawer / Sheet(最高一级视觉容器) | — |
rounded-full |
— | 头像 / 徽章 | — |
组件分层原则:交互控件从小到大遵循
md → lg → xl → 2xl → 3xl → 4xl依次递增,容器级别越大(对话框、卡片)圆角越大,行内小控件(checkbox、badge)圆角越小。新组件设计时先确定"层级",再从表中取值,不要自创中间值。
4.4 阴影(唯一官方取值)
| Token | 用途 |
|---|---|
shadow-md |
Card 默认阴影 |
shadow-lg |
Combobox / 下拉菜单 |
shadow-xl |
Dialog / Sheet / Drawer / Sidebar 菜单 |
规则:禁止新代码使用自定义阴影任意值(如 shadow-[0_6px_15px_rgb(...)])。如确需强调阴影(例如渐变主按钮的"投色阴影"),必须先在本文档中补充为具名 token 后才能使用。
4.5 边框
- 默认宽度
1px(Tailwindborder)。 - 输入类组件:默认
border-transparent,focus 时focus-visible:border-ring+focus-visible:ring-3 focus-visible:ring-ring/30。 - 危险态:
aria-invalid:border-destructive+aria-invalid:ring-3 aria-invalid:ring-destructive/20。 - 边框颜色统一使用
border-border(--color-line),禁止再写border-[#dfe6ee]等任意 hex(见 §2.7)。
4.6 布局
- 页面容器:
min-width: 1120px,桌面优先布局(当前产品定位不适配移动端,如需移动端适配需局部覆盖,不改全局)。 - 侧栏宽度:展开
16rem/ 收起3rem/ 移动端18rem。 - 两栏布局参考:
grid-cols-[310px_minmax(0,1fr)] max-xl:grid-cols-[285px_minmax(0,1fr)]。 - Dashboard 网格参考:
min-[1201px]:grid-cols-[minmax(0,1.6fr)_minmax(310px,0.9fr)] max-[1200px]:grid-cols-1。
4.7 断点
使用 Tailwind v4 默认断点:sm 40rem / md 48rem / lg 64rem / xl 80rem / 2xl 96rem,不自定义。响应式优先用 max-xl: / max-[1200px]: / sm: 等既有写法保持一致性。
5. 组件视觉规范(强制规格,可用任意技术栈实现同等效果)
以下为各组件的强制视觉规格。使用 React + shadcn 的团队直接复用
app/components/ui/*;使用其他框架(Vue/Ant Design/Element Plus 等)的团队,必须在自己的组件层重新实现,但颜色、圆角、尺寸、状态视觉必须与下表完全一致。
5.1 Button
- 圆角
rounded-4xl;字号默认text-sm;字重font-medium;过渡transition-all。 - 尺寸:默认
h-9 px-3/xs h-6 px-2.5/sm h-8 px-3/lg h-10 px-4/icon 36×36/icon-xs 24×24/icon-sm 32×32/icon-lg 40×40。 - 状态:default
bg-primary+ 白字;hoverbg-primary/80;activetranslate-y-px;focusborder-ring+ring-3 ring-ring/30;disabledpointer-events-none opacity-50;invalidborder-destructive ring-3 ring-destructive/20。 - 内部 svg 未指定尺寸时自动
size-4(16px)。
5.2 Input
- 圆角
rounded-3xl;高度h-9(36px);字号text-sm;背景bg-input/50。 - 状态:placeholder
text-muted-foreground;focusborder-ring(无 ring 阴影);disabledcursor-not-allowed opacity-50;invalidborder-destructive。
5.3 Textarea
- 圆角
rounded-2xl;最小高min-h-16(64px);不可手动 resize;内边距px-3 py-3;focus 额外带ring-3 ring-ring/30。
5.4 Checkbox
- 尺寸
size-4(16px);圆角rounded-md(6px,统一自原rounded-[5px]);背景bg-input/90。 - 状态:checked
border-primary bg-primary+ 白色CheckIcon;focusborder-ring ring-3 ring-ring/30;disabledcursor-not-allowed opacity-50;invalidborder-destructive ring-3 ring-destructive/20。
5.5 Combobox / Select
- Trigger 与 Input 一致,右侧
ChevronDownIcon size-4 text-muted-foreground。 - Content:圆角
rounded-3xl,背景bg-popover,阴影shadow-lg,ring-1 ring-foreground/5。 - Item 右侧固定
size-4的CheckIcon占位槽;Separator-mx-1.5 my-1.5 h-px bg-border。 - 入场:按 side 滑入 +
fade-in-0 zoom-in-95,约 100ms。
5.6 Card
- 圆角
rounded-4xl;背景bg-card;阴影shadow-md;ring-1 ring-foreground/5;内边距通过--card-spacing(default 24px / sm 16px)。 - 子区块:
CardTitle(text-base font-medium)/CardDescription(text-sm text-muted-foreground)/CardContent/CardFooter。
5.7 Table
- 外包
div.overflow-x-auto,表格本体w-full text-sm。 TableRow:border-b,hover:bg-muted/50,选中data-[state=selected]:bg-muted。TableHead:高h-12(48px),内边距px-3,font-medium,whitespace-nowrap。TableCell:内边距p-3,不换行;TableCaption:mt-4 text-sm text-muted-foreground。
5.8 Dialog / Sheet / Drawer
| 类型 | 圆角 | 阴影 | 背景 | 进场动画 |
|---|---|---|---|---|
| Dialog | rounded-4xl |
shadow-xl + ring-1 ring-foreground/5 |
bg-popover |
fade-in-0 zoom-in-95 ~100ms |
| Sheet | rounded-4xl |
shadow-xl |
bg-popover |
按 side 平移 2.5rem ~200ms |
| Drawer | rounded-4xl border border-popover |
shadow-xl |
bg-popover |
duration-450 + cubic-bezier(0.22,1,0.36,1),支持 swipe |
- 遮罩层统一
bg-black/30+supports-backdrop-filter:backdrop-blur-sm。 - 关闭按钮:右上
top-4 right-4,icon-sm ghost(32×32,浅灰背景),内含XIcon。 - 三种动画时长差异属官方设计,禁止拉平统一:对话框类交互 ≤ 200ms,抽屉/底栏类模拟物理滑动 ≤ 450ms。
5.9 AlertDialog
与 Dialog 同布局,唯一差异:标题字号 text-lg(Dialog 为 text-base),用于强调警示内容。
5.10 Tooltip
- 圆角
rounded-xl;背景bg-foreground(反色);文字text-background;字号text-xs;内边距px-3 py-1.5。 - 箭头:
size-2.5 rotate-45 rounded-[2px],与背景同色。 - 进场:
fade-in-0 zoom-in-95,约 100ms,按 side 滑入。
5.11 Toast(Sonner)
通过 CSS 变量桥接品牌色,禁止脱离变量单独定义 toast 颜色:
--normal-bg: var(--popover);
--normal-text: var(--popover-foreground);
--normal-border: var(--border);
--border-radius: var(--radius);
图标统一 size-4:CircleCheckIcon / InfoIcon / TriangleAlertIcon / OctagonXIcon / Loader2Icon animate-spin。
5.12 Sidebar
- 宽度:展开
16rem/ 收起3rem/ 移动端18rem。 - 深色专属主题:背景
var(--sidebar-background)、文字var(--sidebar-foreground)、强调色var(--sidebar-primary)、选中态背景var(--sidebar-accent)(必须引用变量,禁止硬编码 hex,见 §2.5)。 - 顶部装饰渐变:
radial-gradient(circle at 10% 1%, rgb(28 105 186 / 25%), transparent 27%), var(--sidebar-background)。 - 收起按钮图标:
PanelLeftIcon(16px)。
5.13 Skeleton / Separator
- Skeleton:
animate-pulse rounded-2xl bg-muted。 - Separator:
shrink-0 bg-border,水平h-px w-full,垂直w-px self-stretch。
5.14 InputGroup
InputGroup / InputGroupAddon(inline-start / inline-end / block-start / block-end)/ InputGroupButton / InputGroupText / InputGroupInput / InputGroupTextarea;addon 点击时焦点转交给兄弟 <input>。addon 文本 text-muted-foreground text-sm font-medium;kbd 元素 rounded-3xl bg-muted-foreground/10 px-1.5。
5.15 Legacy 共享视觉类(仅用于维护存量页面,新代码禁止新增引用)
以下类色值已在本文档中被官方 token 覆盖,新页面不得再引用这些类;修改已使用这些类的旧页面时,应顺势替换为 §5.1–§5.14 的现代规格:
| 类 | 视觉规格(供比对迁移) |
|---|---|
.icon-button |
34×34,边框改为 border-border,圆角改为 rounded-md,hover 背景改为 bg-muted |
.avatar |
34×34 圆形,渐变改为 linear-gradient(135deg, var(--color-brand), var(--color-brand-strong)) |
.primary-button |
迁移为 Button(variant="default"),渐变改为 var(--color-brand) → var(--color-brand-deep) |
.secondary-button |
迁移为 Button(variant="outline") |
.button-spinner |
迁移为 Loader2Icon animate-spin(Toast/Button loading 态统一图标方案,见 §6.1) |
6. 图标与动效
6.1 图标
- 图标库:
lucide-react(线条 1.5px 描边风格),新代码必须使用该图标库;若因技术栈限制需换库,必须保证线条粗细、视觉重量与 lucide 一致。 - 尺寸规范:
size-4(16px,按钮/菜单项默认)/size-3.5(14px,Checkbox)/size-2.5(10px,Tooltip 箭头)。 - Button 内 svg 未指定尺寸时自动
size-4,新实现须遵循此约定。 - 官方高频图标:
XIcon/CheckIcon/ChevronDownIcon/PanelLeftIcon/CircleCheckIcon/InfoIcon/TriangleAlertIcon/OctagonXIcon/Loader2Icon。所有 loading 态一律使用Loader2Icon animate-spin,禁止再实现新的 spinner 动画(替代原.button-spinner+spinkeyframes)。
6.2 过渡时长(唯一官方取值)
| Token | 用途 |
|---|---|
duration-100 |
Dialog / AlertDialog / Sonner 进出 |
duration-150 |
Sheet 遮罩 |
duration-200 |
Sidebar / Sheet 主体 |
duration-450 |
Drawer(模拟 iOS 滑动手感,唯一允许超过 200ms 的场景) |
duration-0 |
手势拖拽(swipe)中临时禁用过渡 |
规则:新增弹层组件必须归类到以上五档之一,不得自创新的时长值。
6.3 缓动函数
| Token | 用途 |
|---|---|
ease-linear |
旋转 / 进度条 |
ease-in-out |
通用过渡 |
ease-out |
模态入场 |
ease-[cubic-bezier(0.32,0.72,0,1)] |
Drawer 遮罩 |
ease-[cubic-bezier(0.22,1,0.36,1)] |
Drawer 主体("expo out"手感) |
6.4 自定义关键帧
| keyframes | 时长 / 缓动 | 用途 |
|---|---|---|
shimmer |
1.3s linear infinite | 骨架屏背景流光(.tree-skeleton-bar) |
lock-pulse |
1.8s ease-in-out infinite | 编辑中状态点呼吸(50% 处 opacity 0.5 + scale 0.78) |
modal-in |
0.18s ease-out | 弹窗从 translateY(8px) scale(0.985) 进入 |
spin |
0.7s linear infinite | 已废弃,新代码统一用 animate-spin(Tailwind 内建) |
toast-in已废弃(Sonner 接管),新代码不得再引用。
6.5 通用动画工具
animate-in/animate-out(shadcn tw-animate-css 工具类)。data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95/data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95—— 弹层组件必须遵循此统一动效模式。data-[side=...]:slide-in-from-{top|bottom|left|right|inline-start|inline-end}-2—— 弹出层按侧滑入的唯一官方写法。animate-pulse(Skeleton)/animate-spin(Loader)。
7. 命名与代码风格
7.1 文件 / 目录
- 路由文件集中在
app/routes/,业务页面按域拆到app/features/{module}/。 - 共享原语在
app/components/ui/<name>.tsx,域内共享在app/components/common/<Name>.tsx。 - 工具函数:
app/lib/utils.ts(cn()=twMerge(clsx(...)))。 - 样式入口:只允许一个 CSS 文件
app/app.css,由app/root.tsx唯一一次import "./app.css"引入;禁止新增分散的样式文件。
7.2 组件命名
- UI 组件函数名使用 PascalCase:
Button/CardHeader/DialogTitle/SidebarMenuButton。 - 每个 UI 元素必须带
data-slot="..."属性(如button/card-header/dialog-content),便于父级选择器和自动化测试定位。
7.3 类名拼接
- 统一用
cn(...)(~/lib/utils,即twMerge(clsx(...)))拼装类名,禁止手写字符串模板拼接类名。 - 组件变体用
cva(...)描述(参考Button/InputGroupAddon)。 - 非 Tailwind 技术栈:最终输出的类名/样式必须与 §2–§6 的视觉规格一致。
7.4 CSS 类命名约定
- shadcn 风格类无 BEM,纯功能化(
card-title/dialog-content),依赖data-slot+ Tailwind 工具类定位。 @layer utilities中的历史类沿用 kebab-case(如scrollbar-thin/dashboard-hero-shell等),新增该层的类也必须用 kebab-case。- 颜色 / 间距 token 优先:新组件必须优先使用 §2/§4 的语义 token(
bg-primary/text-foreground/border-border),禁止写裸 hex 或任意值;确无对应 token 时,先补充 token 定义,再使用。
7.5 路径别名
"~": "frontend/app"
"components": "~/components"
"utils": "~/lib/utils"
"ui": "~/components/ui"
"lib": "~/lib"
"hooks": "~/hooks"
7.6 项目依赖版本(参考,非强制技术选型)
| 角色 | 库 | 版本 |
|---|---|---|
| 原语 | @base-ui/react |
^1.7.0 |
| 变体 | class-variance-authority |
^0.7.1 |
| 类合并 | clsx + tailwind-merge |
^2.1.1 / ^3.6.0 |
| 图标 | lucide-react |
^1.33.0 |
| 样式 | tailwindcss + @tailwindcss/vite |
^4.2.2 |
| 动画 | tw-animate-css |
^1.4.0 |
| Toast | sonner |
^2.0.8 |
| 路由 | react-router / @react-router/dev |
^8 |
| 状态 | zustand |
^5.0.14 |
| 表格 | @tanstack/react-table |
^9.1.2 |
新模块/新项目如使用其他技术栈(Vue + Naive UI / Element Plus / Ant Design 等),必须按 §2/§3/§4/§6 的视觉规格在自己的主题系统中重新定义等价 token,保持视觉一致。
8. app.css 需新增的官方 Token(落地清单)
本文档 v2.0 相比 v1.0 新增/固化了以下 token,必须在
app.css的@theme中补充定义,作为本规范落地的第一步:
@theme {
/* 字号 */
--text-2xs: 0.625rem; /* 10px */
--text-3xs: 0.5625rem; /* 9px */
--text-4xs: 0.5rem; /* 8px */
/* 字重 */
--font-weight-medium-plus: 650;
/* 品牌色补充 */
--color-brand-deep: #0e5bad;
/* 中性色补充 */
--color-ink-caption: #748598;
/* 间距补充 */
--spacing-page-x: 22px;
--spacing-button-x: 15px;
--spacing-gap-icon: 7px;
--spacing-gap-sm: 5px;
--spacing-gap-md: 9px;
}
落地后需同步在 Tailwind 中暴露对应工具类(如 font-medium-plus),并对 §2.7、§4.3、§5.15 中列出的旧任意值做替换。
9. 跨技术栈适配指引
若其他系统/新项目不使用 React + Tailwind + shadcn 技术栈,请按以下方式对齐:
- 色彩:将 §2 全部 CSS 变量原样复制为自己主题系统的变量(如 Ant Design 的
token、Element Plus 的 CSS 变量、Vue 的 SCSS 变量),变量名可保留--color-*前缀便于跨项目检索。 - 字体:引入同一份
Inter-Variable.ttf字体文件,字号阶梯必须与 §3.2 表格一一对应(值相同,token 名可按自身框架习惯命名,但需在文档中注明与本表的映射关系)。 - 圆角/间距/阴影:直接照抄 §4 的像素值,不需要用相同的 Tailwind 类名,但数值必须相等。
- 组件视觉:对照 §5 逐项还原状态(default/hover/active/focus/disabled/invalid)与尺寸,不要求相同 DOM 结构。
- 动效:过渡时长与缓动函数直接照抄 §6.2/§6.3 数值。
- 完成对齐后,在自己项目的 README 或设计文档中注明"视觉规范参照 STYLE_GUIDE.md vX.X",便于后续版本追踪。
附:shadcn 配置(参考)
{
"style": "base-luma",
"tsx": true,
"tailwind": { "config": "", "css": "app/app.css", "baseColor": "neutral", "cssVariables": true },
"iconLibrary": "lucide",
"aliases": {
"components": "~/components",
"utils": "~/lib/utils",
"ui": "~/components/ui",
"lib": "~/lib",
"hooks": "~/hooks"
}
}
版本摘要:React/React DOM 19.2.7 · React Router 8 · Tailwind CSS 4.2.2 · @tailwindcss/vite 4.2.2 · @base-ui/react 1.7.0 · class-variance-authority 0.7.1 · lucide-react 1.33.0 · shadcn CLI 4.19.0 · sonner 2.0.8 · tw-animate-css 1.4.0 · tailwind-merge 3.6.0 · zustand 5.0.14。