怎么用这份表
每张卡片底部那行 照抄这句,是这个概念的专业表述,可以直接抄进 prompt。
编号只是查阅用的,相当于这份表的页码。模型不知道"02"指什么 —— 别把编号发给它,发那句具体的话。
不用从头读。先看下面的分层图,再扫第二部分看实物,最后回来查具体概念。
先看这张:30 个原子分在哪几层
THE STACK · 从上到下 = 先决定到后决定
做界面是自上而下的一串决定。上面几层决定"这东西对不对",下面几层决定"这东西齐不齐"。
新手常见的卡点是从最底层开始纠结 —— 一上来就问"圆角该用几像素",而那一层恰恰是最不需要你操心的。
L0意图
这一屏给谁看?他来这儿要完成什么?完成了是什么样?
这层没有原子只能你自己定
L1信息层级
哪个最重要、哪些是一组的?
这一层错了,下面做得再精细也白搭。
L2骨架布局
内容怎么排?屏幕变窄怎么办?多密合适?
L3组件与状态
用什么零件?每个零件有哪些"样子"?
没数据、加载中、出错了分别长什么样?
L4数值标度
具体几像素、什么颜色?
最厚的一层,但也是最该一次性写进配置文件、之后不用再想的一层。
第一部 / PART ONE
原子 —— 30 个可以指名道姓的东西
分五组。前两组是「度量」,决定界面是否一致;第三组是「原则」,决定界面是否好看;后两组是「结构」,决定界面是否好用。
组 A
度量与排版 METRICS & TYPE · 01—08
01
间距标度 Spacing Scale
所有间距只能从一个固定档位表里挑,通常是 4 的倍数。界面里永远不该出现 13px、17px、23px —— 那是"随手调的",眼睛看不出为什么,但整体会散。
徽章、胶囊这类小元件常还需要一个 2px 的半档,页面级留白可以往上取 96;只要仍在同一张表上,就不算破例。
↑ 这九档覆盖 95% 的场景。档位之间跨度越往上越大 —— 因为大尺寸上 4px 的差别人眼看不见。
照抄这句所有间距对齐到 4pt 标度:常用 4/8/12/16/24/32/48/64,小元件内边距可用 2,页面级留白可用 96。不要出现这张表以外的数值。
02
亲密性 Proximity
间距编码关系 —— 靠得近的元素,人眼自动认为是一伙的。这是整个 UI 设计里最重要的一条,也是"业余感"最大的来源:标题离自己的正文,比离上一段还远。
照抄这句按亲密性重排间距:组内元素 8,组之间 24 或 32,保证组间至少是组内的两倍。
03
字号标度 Type Scale
字号同样只能从档位挑,档位由一个比例数连乘生成(常用 1.2 / 1.25 / 1.333)。比例越大层级越戏剧化,越小越克制。整个界面通常只需要 5–7 档。
- 39 / display层级最高的数字
- 31 / h1页面标题
- 25 / h2区块标题
- 20 / h3卡片标题
- 16 / base正文,一切的基准
- 14 / sm辅助说明、表格
- 12 / xs标签、时间戳
↑ 基准 16,比例 1.25。相邻两档差别必须一眼可辨 —— 15 和 16 并存是纯粹的噪音。
照抄这句字号收敛到 12/14/16/20/25/31/39 七档(基准 16、比例 1.25),去掉所有档位外的字号。
04
字重 Font Weight
粗细。整个界面最多用三档(例如 400 正文 / 500 强调 / 700 标题)。新手的通病是靠加粗制造层级,结果满屏都是粗体 —— 全都在喊等于没人在喊。
照抄这句字重只保留 400 / 500 / 700 三档,正文一律 400,不要用加粗来做层级。
05
行高 Line-height
行与行的垂直距离,写成字号的倍数。规律:字号越大,行高倍数越小。正文 1.5–1.7,标题 1.1–1.25。行高不够读着窒息,行高过大句子会散架。
行高是排版里最容易被忽略、又最影响阅读体感的一项。它决定了眼睛从一行末尾跳回下一行开头时,是否会跳错行。中文因为字形方正、没有升降部,通常比英文再需要多一点行高 —— 正文给到 1.7 也不过分。
↑ 拖到 1.2 感受窒息,拖到 2.2 感受散架。这段文字的合适值大约在 1.6–1.75。
照抄这句正文 line-height 1.65,标题 1.15,不要用统一行高。
06
行长 Measure
一行能放多少字符。英文 45–75 字符,中文 30–45 字。超过就会跳错行。CSS 里一个 max-width: 65ch 就搞定 —— 这是性价比最高的一条排版规则。
排版上唯一一条几乎不需要判断力的规则,就是限制行长。眼睛在一行结束后要做一次"回扫"动作,找到下一行的起点。行越长,这次回扫的落点误差越大,读者就越容易重复读同一行或者跳过一行。这个上限跟屏幕多宽没关系,只跟人眼有关系,所以再宽的显示器上,正文也不该铺满。
↑ 拖到 120ch 试试回扫。屏幕宽不是让正文变宽的理由,是让两侧留白变宽的理由。
照抄这句正文容器加 max-width: 65ch,不要让文字铺满整个屏幕宽度。
07
字距 Letter-spacing / Tracking
字符间距。规律和行高一样反着来:字越大越要收紧(负值),字越小越要放松(正值)。全大写和小号标签一定要放松,否则糊成一团。这是"廉价"和"精致"之间最细微也最有效的一刀。
大标题 · 收紧
收紧的大标题
letter-spacing: -0.035em
正文 · 不动
正常大小的正文,字距保持 0,不要画蛇添足。
letter-spacing: 0
小号大写标签 · 放松
SECTION LABEL · 区块标签
letter-spacing: 0.16em
照抄这句28px 以上标题 letter-spacing -0.03em;小号大写标签 +0.14em;正文保持 0。
08
圆角标度 Radius Scale
圆角也要成档(2 / 4 / 8 / 12 / 999)。而且有一条硬公式管嵌套:外圆角 = 内圆角 + 内边距。违反了会看到两条弧线不同心 —— 说不出哪不对,但就是别扭。
错 · 内外同圆角
外 8 · 内 8 · padding 12
对 · 外 = 内 + padding
外 20 · 内 8 · padding 12
↑ 盯着两个图形的左上角看。右边那对弧线是同心的,左边不是。
照抄这句圆角用 2/4/8/12 四档;嵌套时外层圆角 = 内层圆角 + 内边距。
组 B
色彩与深度 COLOR & DEPTH · 09—14
09
色阶 Color Ramp
一个颜色不是一个色值,是一条从 50 到 950 的梯度。你要的从来不是"蓝色",而是"蓝-600 做按钮、蓝-50 做背景、蓝-800 做文字"。现代做法用 OKLCH 生成,保证每一档的感知亮度均匀。
↑ 常用分工:50/100 背景 · 200/300 描边 · 500/600 主色/按钮 · 700/800 文字 · 900/950 暗色底
照抄这句用完整 50–950 色阶,不要临时凑色值:背景用 -50,描边用 -200,按钮用 -600,文字用 -800。
10
语义色 / Token 三层 Semantic Tokens
Token 是三级的,这才是它真正的价值所在。改主题只动第二层,第一层永远不动。有了这层结构,"把危险色调一下"是一次改动,没有它就是全局搜索替换。
Tier 1 · 原始
teal-600
red-600
gray-800
space-4
只是色值和数值,不带任何含义。永不直接使用。
Tier 2 · 语义 ←改这层
color-primary
color-danger
text-body
space-inline
带含义。换主题、做暗色、改品牌色,只改这一层的指向。
Tier 3 · 组件
button-bg
alert-border
card-padding
input-radius
组件私有。只有当某个组件需要偏离通用规则时才建。
照抄这句建立三层 token:primitive → semantic → component,组件里只准引用语义层,禁止硬编码色值。
11
中性色 Neutrals
界面 90% 的面积是中性色。两条规则:不要用纯黑纯白(#000 在屏幕上过刺,像挖了个洞);中性色要带一点点色相偏向,偏向主色的方向 —— 纯灰读起来像"没选过"。
纯黑纯白 · 纯灰
标题文字 #000
辅助文字 #808080,在 #FFFFFF 上。对比生硬,灰色发脏。
选过的中性色
标题文字 #14181A
辅助文字 #606A6E,带青绿偏向,和主色同族。整体更沉静。
照抄这句不要用 #000 / #FFF;中性色向主色的色相偏 2–5 度,正文用 gray-800 而不是纯黑。
12
对比度 Contrast Ratio
前景色和背景色的亮度比值,有客观数值可算。及格线(WCAG AA):正文 4.5:1,大字和 UI 元件 3:1。这不是加分项,是及格线 —— 而"字太浅看不清"是 AI 生成界面最高频的毛病。
↑ 白底上的真实比值。#767676 是白底正文的极限,再浅一点就不及格。占位符、禁用态最容易翻车。
照抄这句所有文字对比度必须过 WCAG AA:正文 ≥4.5:1,大字和图标 ≥3:1,把每个色对的比值算给我看。
13
海拔 / 阴影阶梯 Elevation
阴影不是装饰,是"这东西离页面多远"的编码。要成阶梯(4–5 档),越高的层阴影越大越散。而且真实的阴影是向下偏移的(光从上来),不是四面均匀发光。
0 · 贴地
表格行、分割区
1 · 卡片
列表卡
2 · 悬浮
hover 抬起
3 · 浮层
下拉、气泡
4 · 模态
对话框
↑ 注意 y 偏移和模糊半径是一起增长的。只调 blur 不调 y,阴影会像雾而不像影。
照抄这句阴影用 5 档海拔阶梯,y 偏移和模糊半径同步增长;下拉用第 3 档,模态用第 4 档。
14
暗色模式 Dark Mode
暗色不是把颜色反转。三条独立规则:① 降饱和 —— 亮色在暗底上会刺眼振动;② 用「提亮」代替「投影」表达层级 —— 黑底上的黑影是看不见的;③ 底色不要纯黑,用 #0C0F10 这类近黑。
↑ 右边那张卡没有任何阴影,"浮起来"完全靠比背景亮。这就是暗色下的海拔。
照抄这句做暗色时不要反转:降低饱和度,用背景提亮代替阴影表达层级,底色用近黑不用纯黑。
组 C
视觉原则 PRINCIPLES · 15—20 · 这组回答"说不出哪不对"
15
视觉层级 Visual Hierarchy
让人一眼知道先看哪儿。你手上有六种手段,按有效强度排序如下。新手只会用「尺寸」和「字重」,于是所有元素同时在喊;老手先用「留白」和「明度」,安静得多也有效得多。
照抄这句层级优先用留白和明度对比来做,不要靠加大字号和加粗;每屏只允许一个视觉焦点。
16
留白 White Space
留白不是"还没填的地方",是主动划出的呼吸区。分外白(区块之间)和内白(元素内部 padding)。密的界面显得廉价而焦虑,不是因为元素丑,是因为没给它们空间。
内白不足
本月账单
2026 年 7 月 · 已出账
¥ 1,284.00
内白 20 / 分组间距 14
本月账单
2026 年 7 月 · 已出账
¥ 1,284.00
照抄这句卡片内边距至少 20,区块之间至少 48;宁可减内容也不要减留白。
17
对齐 Alignment
每条隐形的对齐轴都是一次视觉承诺。一屏里的对齐轴越少越整齐 —— 通常两条足够(一条主轴 + 一条缩进轴)。新手界面常有四五条互不相干的左边界,说不出哪乱,但就是乱。
照抄这句把左对齐轴收敛到两条:主轴和一条 30px 缩进轴,去掉所有零散缩进。
18
一致性 / 重复 Consistency & Repetition
同一种东西必须长得完全一样。三张并排卡片,圆角一个 6 一个 8 一个 10,人眼察觉得到但意识不到 —— 结果是"这页面有点廉价"。一致性是设计系统存在的全部理由。
圆角 5 · pad 11/13
圆角 9 · pad 15/10 · 边框 2
圆角 14 · pad 9/16 · 字号 13.5
↑ 这三张卡"内容一样、参数全不同"。看着别扭却说不出所以然 —— 这就是一致性缺失的典型症状。
照抄这句抽出一个统一的卡片组件,所有卡片共用同一套圆角/内边距/边框,不允许逐个微调。
19
视觉重量与平衡 Visual Weight
每个元素都有"视觉重量",由面积 × 明度 × 饱和度共同决定。一小块高饱和的色,重量等于一大片灰。所以主按钮不用做大,只要它是全屏唯一的实心色块就够。
↑ 面积差 5 倍,视觉重量却接近。推论:整页只能有一个高饱和实色块,那就是你要用户点的地方。
照抄这句整屏只允许一个高饱和实心按钮,其余动作用描边或纯文字按钮。
20
光学修正 Optical Adjustment
数学居中 ≠ 看着居中。三角形、图标、引号、圆形都要手动补偿。经典案例是播放按钮 —— 三角形几何居中时永远看着偏左,必须右移约 8%。这条是"精致"的最后一公里。
↑ 原理:三角形的视觉重心在几何中心偏左,因为右侧是个尖,面积在左边。
照抄这句播放三角、图标做光学居中补偿,不要只用 flex center。
21
gap 而非 margin Spacing Ownership
一条能消掉一半布局 bug 的规则:间距属于容器,不属于元素。子元素不该自带 margin 来决定"我离别人多远",应该由父容器的 gap 统一决定。margin 会塌陷、会叠加、会在复用时打架。
子元素自带 margin
.card { margin-bottom: 16px }
.card:last-child { margin-bottom: 0 }
← 永远要写这条补丁
← 换到横向布局就废了
父容器 gap
.list {
display: flex;
flex-direction: column;
gap: 16px;
}
← 没有补丁,方向随便改
照抄这句用 flex/grid + gap 布局,禁止子元素自带 margin,也不要写 :last-child 清间距的补丁。
22
Flex 还是 Grid Flex vs Grid
心智模型只有一句话:Flex 管一维(一行或一列),Grid 管二维(行列同时管)。工具栏、按钮组、列表项内部 → Flex。页面骨架、卡片墙、表单双列 → Grid。
Flex · 一维
元素排成一条线,各自决定占多宽。工具栏、导航、行内元素。
Grid · 二维
先画出行列骨架,元素再往格子里放、可以跨格。页面布局、卡片墙。
照抄这句页面骨架用 Grid,组件内部一行元素用 Flex,不要用 Flex 硬凑二维布局。
23
栅格 Grid System
把内容区横向切成 12 等份(因为 12 能被 2/3/4/6 整除),所有元素的宽度都是整数份。加上一个容器最大宽度(常见 1120–1280),页面就不会在大屏上散架。
span 8 · 主内容
span 4 · 侧栏
span 4
span 4
span 4
span 6
span 6
↑ 红色是栅格轨道。8+4、4+4+4、6+6 —— 常用组合就这几种,够用了。
照抄这句用 12 栏栅格,gutter 24,容器最大宽 1200;主内容 span 8、侧栏 span 4。
24
响应式 Responsive & Container Query
老做法是断点(看屏幕多宽)。新做法是容器查询(看自己所在的容器多宽)—— 同一个卡片放侧栏里是竖版、放主区里是横版,组件自己就知道,不用外面配合。
↓ 拖右下角改变宽度。断点在 420px,卡片自己会切换布局。
容器查询演示卡
它不关心屏幕多宽,只关心自己被塞进了多宽的盒子。
断点还是要的(页面骨架级),但组件级一律用 container query,复用性完全不同。
照抄这句页面骨架用媒体查询断点,组件内部改用 container query,让组件自适应容器而不是屏幕。
25
密度 Density
同样的信息,可以铺得紧也可以铺得松。密度由使用场景决定:专业工具(金融终端、后台表格)要紧,让人一屏看到更多;消费产品要松,让人放松。一个产品里密度必须统一。
密度
| 任务 | 负责人 | 状态 | 耗时 |
| 重写 IR 映射层 | Liang | 进行中 | 4.2h |
| 沙箱策略对齐 Codex | Liang | 已完成 | 11.0h |
| 模型调用退避重试 | Liang | 已完成 | 2.5h |
| 环境上下文注入 | Liang | 待评审 | 6.8h |
↑ 内容一个字没变,只改了行内边距(5 / 10 / 17)。密度是一个 token,不是逐处硬编码。
照抄这句把密度抽成 token(compact/cozy/roomy),全站统一用一档,不要逐个组件调 padding。
组 E
组件与交互 COMPONENTS & INTERACTION · 26—30
26
组件解剖 Anatomy
每个组件都能拆成有名字的部位。学会这套黑话,你就能精确指到某一块:不是"右边那个小东西",而是"trailing 区的 badge"。几乎所有组件都是这四段结构。
主标签 Label辅助说明 Supporting text
3
→
leading
label + supporting
badge
trailing
↑ 按钮、列表项、输入框、菜单项、卡片头 —— 全是这个结构。container / leading / label / trailing。
照抄这句在 trailing 区加一个计数 badge,leading 保持头像,label 两行不变。
27
状态 States
一个可交互元素不是一个样子,是九个样子。模型默认只给你 default 和 hover —— 剩下七个要你主动要。其中 focus-visible 最常被漏,而它是键盘用户唯一的方向感。
default
hover
active
focus-visible ←最常漏
disabled
loading
selected
danger
ghost / 次级
↑ 上面第一个按钮是真的,可以 hover、点击、按 Tab 聚焦试试。
照抄这句给每个可交互元素补齐九态:default/hover/active/focus-visible/disabled/loading/selected/error/empty。
28
变体矩阵 Variant Matrix
定义一个组件 = 填一张二维表:变体(primary / secondary / ghost / danger)× 尺寸(sm / md / lg)。把表填完,组件就定义完了 —— 这是最容易交给模型的一类活。
照抄这句按 variant×size 矩阵实现按钮:primary/secondary/ghost/danger × sm/md/lg,每格都要有完整九态。
29
界面的五种状态 The Five States
这条对你和模型协作最值钱。任何一块展示数据的区域都有五种状态,而模型默认只做第五种(理想态)。把这五个字当验收清单用,一次能拦下大半返工。
↑ 点标签切换。注意空态不是一片空白 —— 它是引导用户迈出第一步的地方,是新手最重要的一屏。
照抄这句这个模块把五态都做出来:空、加载、部分、错误、理想。空态要有引导文案和主行动按钮。
30
动效 Motion
两个参数:时长(UI 动效 120–300ms,超过 400ms 就觉得卡)和缓动曲线(进场用 ease-out 快起慢停,出场用 ease-in)。linear 是机器人的动法,几乎永远是错的。
↑ 点任意轨道重播。第三条是 linear —— 匀速启动、匀速刹停,现实世界没有东西这么动。
照抄这句过渡统一 150ms ease-out,进场 ease-out、出场 ease-in,禁止 linear,并加 prefers-reduced-motion 兜底。
第二部 / PART TWO
组合 —— 原子拼成的东西
上面 30 个原子,在真实产品里翻来覆去就拼成下面这些。每张卡底部标注了它用到哪几号,点编号跳回定义。看到眼熟的先看,那说明你正在做它。
组 F
组件组合 COMPONENTS · 21 种,覆盖 90% 的界面元素
按钮组 Button Group
一组动作里只能有一个主按钮 —— 那是你想让人点的。
表单字段 Form Field
标签 + 输入 + 帮助文字 + 错误。四段结构缺一不可。
内容卡片 Card
整个 Web 最泛用的容器。缩略图 + 标题 + 描述 + 页脚。
Agent Harness 第 23 章
把 IR 层做成 provider-neutral,用 Anthropic Messages 映射层验证。
列表行 List Row
头像 + 双行文字 + 状态 + 箭头。移动端的主力结构。
skills-hub 部署154 runner · 转发式 CI
成功
liangai.org 统计Umami · 五站点
排队
沙箱策略同步sandbox-exec + bwrap
失败
数据表 Data Table
数字必须右对齐 + 等宽数字,否则位数对不齐没法比较。
| 服务 | 区域 | 月成本 |
| Oracle VPS | ap-tokyo | 0.00 |
| Cloudflare Pages | global | 0.00 |
| Runner 154 | self-host | 42.50 |
| 域名续费 | — | 9.87 |
徽章与标签 Badge / Tag / Chip
状态不能只靠颜色 —— 色盲用户看不见,必须配文字。
● 运行中
● 已失败
● 已归档
Beta
v2.4.1
12
指标块 Stat Tile
先给结论(大数字),再给上下文(变化率)。含迷你趋势线。
标签导航 Tabs / Nav
当前位置必须比其他项更重、更深、带下划线。
对话框 Modal / Dialog
危险动作:按钮文案写清楚会发生什么,不要写"确定"。
删除 3 个部署记录?
这些记录会永久移除,关联的构建日志也会一并清除。此操作不可撤销。
提示条 Toast / Alert
错误信息要说清"哪错了 + 怎么办",不要只说"出错了"。
已发布到 liangai.org耗时 38 秒 · 查看部署日志
SSH 密钥被拒绝runner 154 上的 forced-command 不匹配。检查 authorized_keys 第 2 行。
头像组 Avatar Group
负边距叠压 + 描边分隔 + 超出计数。协作产品的标配。
空态 Empty State
新用户见到的第一屏。必须有一个明确的下一步动作。
还没有任何部署
连接一个仓库后,每次 push 都会自动上线。
骨架屏 Skeleton
形状要贴近真实内容,否则加载完会"跳一下"。
分段控件 Segmented Control
2–4 个互斥选项用它,超过就该换下拉了(Hick 定律)。
搜索框 Search Input
leading 放图标,trailing 放清除 —— 典型的 26 号结构。
进度与步骤 Progress / Stepper
超过 1 秒的操作必须给进度,超过 10 秒必须能取消。
构建中 · 步骤 2 / 4
48%
✓ 拉取
● 构建
○ 测试
○ 发布
下拉选择器 Select / Dropdown
选项超过 4 个用它,4 个以内用分段控件 —— 下拉多一次点击才能看到选项。
开关 · 复选框 · 单选 Switch · Checkbox · Radio
三个长得像,规则完全不同:开关立即生效,复选和单选要等提交。
失败时发邮件通知
立即生效
只跑失败过的用例
互斥
面包屑 Breadcrumb
回答"我在哪"。最后一级是当前位置,不可点,而且要比前面几级重。
空间
/
skills-hub
/
测试集
/
回归集 v3
分页器 Pagination
当前页必须明显更重(19 号)。省略号两侧要留首尾页,否则用户跳不到最后。
工具提示 Tooltip
只放补充信息。关键信息不能藏在 tooltip 里 —— 触屏设备根本悬停不了。
按空间 ID 哈希分流,同一空间始终进同一组
分流方式
组 G
页面布局 LAYOUTS · 你需要的几乎都在这 12 种里
下面是骨架平面图,青色块是视觉焦点所在。选布局的方法只有一条:看用户来这一屏是要干什么,不是看它好不好看。
应用外壳 App Shell
侧边导航 + 顶栏 + 内容区。后台系统的默认答案。
仪表盘 Dashboard
先给结论指标,再给明细图表。结论在上,证据在下。
列表-详情 List / Detail
左选右看。邮箱、聊天、工单、日志,全是这个。
设置页 Settings
左侧分类 + 右侧分组表单。每组之间要有明确的分隔。
数据表页 Table View
标题 → 工具栏 → 表格 → 分页。密度和对齐决定成败。
页头 · 标题 + 主动作
工具栏 · 搜索 筛选 批量
表格主体
分页 · 共 248 条
落地页 Landing
Hero → 价值点 → 社会证明 → CTA。垂直叙事,全宽分段。
导航
Hero · 一句话说清楚是什么
特性
特性
特性
CTA · 页脚
居中表单 Centered Form
登录、注册、单一任务。屏幕上不该有第二个焦点。
文档页 Docs
左导航 + 中正文(限宽!)+ 右目录。三栏经典。
顶栏 · 搜索 版本
章节导航
正文 65ch
本页目录
信息流 Feed
单列卡片流 + 右侧辅助栏。移动端直接砍掉右栏。
对开编辑 Split Editor
左编辑右预览。代码、Markdown、设计工具的标配。
分步向导 Wizard
把长表单切成几步。每步只问一件事,永远能退回。
① ━━ ② ━━ ③ 进度条
当前步骤的字段
上一步 ← → 下一步
看板 Kanban
横向列 + 纵向卡。横向滚动,列头要吸顶。
第三部 / PART THREE
上面每一层都有成熟得不能再成熟的实现。你要做的不是造,是选一套然后指名让模型用它。下面按层给,每层选一个就够。
技术栈选完就这么开场
- 用 Tailwind + shadcn/ui,所有间距字号走 Tailwind 标度,组件从 shadcn 装、不要自己写
- 颜色用 Radix Colors 的语义层,图标用 Lucide
- 不要引入任何其他 UI 库,不要自定义标度外的数值
别自己造的东西
- 下拉菜单 / 对话框 / 日期选择器 —— 焦点管理和键盘导航是深坑
- 色阶 —— 手调的色阶在暗色模式一定翻车
- 图标 —— 风格统一比好看重要
- 虚拟滚动 / 表格 —— TanStack Table 已经做完了
上面那张表是库和工具(装进项目里跑的)。这张是规范和文档(拿来读、拿来抄的)—— 全部免费公开。你不需要通读任何一份,需要的是知道遇到什么问题该翻哪一本。
第四部 / PART FOUR
怎么把这些说给模型听
形容词的歧义空间几乎是无限的,编号和数值的歧义空间是有限的。这一部给的是把话说清楚的方式 —— 至于模型怎么响应,取决于模型本身、上下文和你提的其他要求,这份表不做承诺。
项目开场 · 一次性设定,之后不用重复
技术栈:Tailwind + shadcn/ui + Radix Colors + Lucide。不引入其他 UI 库。
标度约束
· 间距只用 4/8/12/16/24/32/48/64
· 字号只用 12/14/16/20/25/31,字重只用 400/500/700
· 圆角只用 2/4/8/12,嵌套时外圆角 = 内圆角 + padding
· 正文 line-height 1.65、max-width 65ch;标题 1.15、letter-spacing -0.03em
硬性要求
· 布局一律 flex/grid + gap,禁止子元素自带 margin
· 每个可交互元素补齐九态,focus-visible 必须可见
· 每个数据区域给出五态:空/加载/部分/错误/理想
· 所有文字过 WCAG AA(正文 4.5:1、UI 元件 3:1)
· 明暗双主题,暗色用提亮代替阴影表达层级
· 过渡 150ms ease-out,禁止 linear,带 prefers-reduced-motion 兜底
工作方式:动手前先列设计决策清单(用了哪几档间距、几级层级、
对比度多少),我确认后再写代码。
但别每次都贴 · 把约束写进项目
上面那段有个弱点:它靠你记得贴,而且模型在长对话里会忘。
可靠性排序是 —— 机器强制 > 文件约定 > 口头提醒。三层都做,别只做第三层。
① 机器强制 · 把标度写进 @theme(Tailwind 4,globals.css)
@theme {
--spacing: 4px; /* p-1=4 p-2=8 p-4=16… 整套自动落在 4pt 网格 */
--text-*: initial; /* 先清空默认字阶 */
--text-xs: 12px; --text-sm: 14px; --text-base: 16px;
--text-lg: 20px; --text-xl: 25px; --text-2xl: 31px;
--radius-*: initial;
--radius-xs: 2px; --radius-sm: 4px; --radius-md: 8px; --radius-lg: 12px;
}
清空默认那两行是关键:标度外的值连类名都不存在,
模型想违反也写不出来 —— 这比任何叮嘱都有效。01 03 08 从此不用再说。
② 文件约定 · 写进 CLAUDE.md / AGENTS.md
放机器管不了的那部分:九态、五态、决策清单、一次只改一层、
禁止子元素自带 margin。每个会话自动加载,不用你贴。
③ 口头提醒 · 上面那段 prompt
降级为临时用途:只在这次要偏离约定时说。
验收也要机器化
npx @axe-core/cli http://localhost:3000 # 12 号对比度 / 焦点 / label
让模型改完自己跑一遍,比肉眼和比「你检查一下」都靠谱。
写成 DESIGN.md · 开源格式,放进仓库就行
上一张卡说的「② 文件约定」,现在有标准答案了:DESIGN.md —— Google Labs
维护的开源格式规范(Apache-2.0)。YAML 前言放机器读的 token,markdown 正文
放人读的理由,文件丢在仓库根目录。
它的字段和这张表几乎一一对应:
前言 colors ← 09 色阶 · 10 语义色 · 11 中性色
前言 typography ← 03 字号 · 04 字重 · 05 行高 · 07 字距
前言 spacing ← 01 间距标度
前言 rounded ← 08 圆角标度
## Layout ← 21 gap · 22 Flex/Grid · 23 栅格 · 24 响应式 · 25 密度
## Elevation ← 13 海拔
## Components ← 26 解剖 · 27 状态 · 28 变体矩阵 · 29 五态
## Do's and Don'ts ← 你自己的取舍
换句话说:前言就是 L4,正文就是 L2 / L3 / L5。
L0 意图那一层它不管 —— 那一层永远是你的。
──── 以下整段可直接抄,数值就是这张表用的那套 ────
---
version: alpha
name: 你的项目名
description: 一句话说清给谁用、解决什么
colors:
primary: "#0C6A72" # 主色:按钮 / 链接 / 焦点环
background: "#F5F5F2" # 页面底
surface: "#FFFFFF" # 卡片 / 面板底
text: "#14181A" # 正文,不用纯黑(11)
muted: "#606A6E" # 次要文字,对底 ≥ 4.5:1(12)
border: "#DFE0DB"
success: "#2C7A52"
danger: "#B4433B"
typography:
h1: { fontFamily: Inter, fontSize: 31px, fontWeight: 700, lineHeight: 1.15, letterSpacing: -0.03em }
h2: { fontFamily: Inter, fontSize: 25px, fontWeight: 700, lineHeight: 1.2, letterSpacing: -0.02em }
h3: { fontFamily: Inter, fontSize: 20px, fontWeight: 600, lineHeight: 1.3 }
body: { fontFamily: Inter, fontSize: 16px, fontWeight: 400, lineHeight: 1.65 }
small: { fontFamily: Inter, fontSize: 14px, fontWeight: 400, lineHeight: 1.55 }
caption: { fontFamily: Inter, fontSize: 12px, fontWeight: 400, lineHeight: 1.5, letterSpacing: 0.04em }
spacing:
xs: 4px
sm: 8px
md: 16px
lg: 24px
xl: 32px
2xl: 48px
3xl: 64px
rounded:
sm: 2px
md: 4px
lg: 8px
xl: 12px
---
## Overview
给 <谁> 用的 <什么>。整体气质:<两三个形容词 + 一个参照物,比如"接近 Linear 的密度">。
## Colors
只用上面的 token,不要临时凑色值(09)。正文用 {colors.text},不要 #000(11)。
任一对文字/背景 ≥ 4.5:1,UI 元件 ≥ 3:1(12)。
暗色模式重新调,不要直接反转;用背景提亮代替阴影表达层级(14)。
## Typography
正文 {typography.body},容器 max-width 65ch(06)。
层级靠留白和明度,不靠加粗(15)。字重只用 400 / 500 / 700(04)。
## Layout & Spacing
一律 flex / grid + gap,禁止子元素自带 margin(21)。
间距只用 spacing 的档位(01)。组内 {spacing.sm}、组间 {spacing.lg} ——
组间至少是组内的两倍(02)。密度取向:<紧凑 / 舒适>(25)。
## Elevation & Depth
层级用阶梯表达,不要随手加阴影(13)。暗色下改用背景提亮。
## Shapes
圆角只用 rounded 的四档(08)。嵌套时外圆角 = 内圆角 + padding。
## Components
每个可交互元素补齐九态,focus-visible 必须可见(27)。
每个数据区域给五态:空 / 加载 / 部分 / 错误 / 理想(29)。空态要有引导文案和一个主行动按钮。
过渡 150ms ease-out,带 prefers-reduced-motion 兜底(30)。
## Do's and Don'ts
Do: <你的取舍>
Don't: 不要引入标度外的数值;不要新增 UI 库;不要用 emoji 当图标。
──── 抄到这里为止 ────
两条要说明白的:
· 正文里引用 token 要用花括号,写成 {colors.primary},这是规范定的。
· 规范目前标的是 alpha,字段可能还会变 —— 抄之前扫一眼上游仓库。
还有一条更要紧的:
有这个文件不等于模型一定照做。它省掉的是「每开一个会话重新解释一遍」,
不是「从此不用检查」。该跑的校验还是要跑(axe / Lighthouse)。
日常返工 · 把感觉翻译成指令
✗ 这个卡片看起来不够精致,你再改改
✓ 按关系重排间距:标题和描述之间 8,卡片之间 24,内边距 20。
标题字重从 700 降到 500,改用留白和明度对比拉层级,不要靠加粗。
外圆角改成 20,让它等于内圆角加内边距。
诊断表 —— 从"感觉"查到"该说什么"
界面不对劲时从左边找,右边整句可以直接发给模型(中间那列的编号是给你查表用的)。
四条能减少来回的习惯
- 给参照物,不给形容词。"按 Linear 的密度和层级来"比"做得高级点"指向明确得多 —— 主流产品的视觉语言在训练数据里出现得足够多。
- 先要决策清单,再要代码。让它把"用了哪档间距、几级层级、对比度多少"讲出来,你在写代码前就能拦下分歧。
- 复盘时说具体项,不说编号。"正文对比度没到 4.5:1、空态没做" —— 编号是你查表用的,模型不认。
- 一次只改一层。让它单独改间距,别同时改颜色和布局,否则你分不清是哪一处让它变好或变坏。
你其实只需要记住五条
- 间距编码关系 —— 组间必须是组内的两倍 02
- 一切都要成档 —— 间距、字号、圆角、阴影 01 03 08 13
- 层级靠留白,不靠加粗 15
- 整屏只有一个焦点 19
- 永远问五态和九态 27 29