ui-craft · diff
git:20261014.c035de9 to git:20261021.c987d4d
9 added, 12 removed. Audit A to A.
---
name: ui-craft
description: 新建、重设计、打磨或审查界面(页面、组件、弹层、落地页)时读,也用于单项的动效、配色、排版、图标、表单反馈、无障碍与移动端适配
---
# UI Craft
项目已有组件、token、lint、DESIGN.md 和平台规范时以它们为准;本文件补它们表达不了的品味和默认取值。
## 开工
1. 读现有 Button、Input、菜单、Dialog、token 和一个相邻页面,全局尺寸沿用项目值。改已有界面时,先 grep 列出同类组件(Tab、Toast、弹层、行菜单、头像、图注、Radio)的全部实例,改在共享实现上,不逐处补。
2. 定主要输入(`pointer`、`touch`、`hybrid`)和一个默认密度(`compact`、`comfortable`、`touch`);组件因业务例外时用语义变体承载。窗口变宽时增加内容、列或面板,控件尺寸固定。原生桌面应用用系统控件尺寸,下表供 Web、Electron 和自绘界面。
3. 新建或大改时,先从请求、README 和代码定主要用户与核心任务;每页一个主要任务,定好层级与焦点再选 Card、分栏、侧栏或长页结构。没有既有品牌时选一个明确视觉方向,直接落到配色、字体、间距和表面层级。
## 动手前按情形读参考
任务涉及左列情形时,写代码前先读右列文件;动效取值、表单与反馈规则、图标描边都在参考里,本文件只有总则。
| 情形 | 读取 |
|---|---|
| 动效、转场、进出场、手风琴、Tab 指示条、弹簧 | `reference/motion.md` |
| 拖拽、swipe、bottom sheet、carousel | `reference/gestures.md` |
| 选图标、描边、品牌 logo、图标动效 | `reference/icons.md` |
- | 表单、Label/Placeholder、校验、Toast/Banner/Tooltip、上传删除保存的反馈 | `reference/forms-and-feedback.md` |
+ | 表单、设置开关、Label/Placeholder、校验、提交状态、Toast/Banner/Tooltip | `reference/forms-and-feedback.md` |
| 删重复页眉、描述、helper、重复 CTA | `reference/content-reduction.md` |
| 字体、字阶、行高、换行截断、混合方向 | `reference/typography.md` |
| 调色板、语义色、对比度、暗色与高对比 | `reference/color.md` |
| 焦点、键盘、读屏播报、命中区、禁用态、缩放重排 | `reference/accessibility.md` |
| 手机上像网页:hover 粘住、100vh、输入放大、安全区、状态栏颜色 | `reference/mobile.md` |
| 审查界面并出报告 | `reference/review.md` |
## 品味
好看现代 = 克制的骨架 + 一个有分量的焦点 + 到位的细节。每屏只有一个视觉焦点,由真实内容或真实交互充当(数据、预览、作品、主输入),字号、体积、彩度和最用心的动效都给它;导航、控件、列表保持扁平克制。减法只删骨架上的噪音,不删焦点与信息。界面显得素、空、普通时,先加强排版层级、换上真实内容、把焦点做足,不加装饰、标签或卡片。焦点需要特效或成品动效件时,按 ui-picks 选库移植。
营销页首屏先让人看懂产品是什么、怎么开始:产品名、一句主张、主行动(下载、安装、试用)和真实产品视觉最醒目,次要卖点后移或收小。缺素材时用 gpt-image 生成产品相关的图,或按 ui-picks 取现成件,不留占位图,也不用文字和卡片凑数。
### 标签与页眉
以下是生成界面最常见的噪音,默认都不加:
- 标题上方的小号大写标签(eyebrow / kicker)。
- 给每节或每张卡加的分类、编号、状态小标签与徽标(01/02/03、「推荐」「NEW」)。
- 页面顶部重复导航当前项的页眉与副标题;Tab 列表常驻可见时,panel 里重复 tab 名的标题。
- 标题、分区、弹层、设置项下面的说明句。机制解释、候选来源、玩法等教学说明收进标签旁的问号 Toggletip;操作前必须知道的范围、门槛、后果直写并持久可见。
标题直接说内容,层级靠字号、字重和间距。标签只在承载用户需要区分的真实状态时出现(未读、失败、已过期)。导航在当前断点被隐藏、页面可经深链独立打开或页面很长时,才显示一个简短标题;省掉可见标题的内容区用 `aria-labelledby` 或准确的 accessible name 保持可定位,文档 `<title>` 随视图更新。
### 其他模板痕迹
- 渐变文字、标题里的斜体强调词、等宽字体的小标签、奶油色或米黄色背景、默认玻璃拟态、无限等尺寸 Card Grid、无业务依据的大数字 Hero。
- - 卡片套卡片、渐变底加内环线、卡片左侧或顶部的彩色条、弹层顶部的彩线。
+ - 卡片套卡片、渐变底加内环线、卡片左侧或顶部的彩色条(有提示语义的 Callout、Alert 除外,颜色走共享语义 token)、弹层顶部的彩线。
- 分割线:弹层、卡片、侧栏、菜单、表单段落的头尾与内容之间,文件、会话、成员这类列表行之间,一律用间距、对齐、hover 底色或轻微底色差分组;只有多列对比的数据表需要行线。确需分隔时用项目里统一的一种虚线或发丝线组件,不手写 border。
- 图标外套的底色方块、圆圈或描边。图标裸放,要分类色就给图标本身着色。
- 状态胶囊(带底色的圆角小标签)、每种状态各配一层彩色底、进行中用绿色。状态由图标与状态词的颜色表达;底色只留给要用户处理的一两种,满屏都上色就不再表示「要你看」;绿色读作完成,进行中用蓝或中性色。
- 同类条目各有各的行数(有的多一行读数、有的没有),时间混写分钟、钟点、秒表。同类条目固定行数与列位,缺的那一格留空;时间只用一种写法。
- 鼠标点击后留下的外圈方框:按钮、卡片、勾选只在键盘聚焦时出环(`:focus-visible`),文本框聚焦只加深边框色。
目标写法:用间距和对齐分组,最用心的动效集中给焦点。去掉一种痕迹后检查有没有换成近亲(分割线变 1px 底边、彩条变彩色左边框、说明句变灰色小字),换了等于没去。
## 密度与控件尺寸
项目没有设计系统时的默认值,平台规范优先:
| Profile | 典型场景 | Button / Input | Icon button | Row | Label | Icon | 水平 padding |
|---|---|---:|---:|---:|---:|---:|---:|
| `compact` | 浏览器插件、桌面工具栏、数据密集工具 | 32px | 28–32px | 28–32px | 13px | 14–16px | 10–12px |
| `comfortable` | 普通桌面应用、设置页、Dialog | 36px | 32–36px | 36–40px | 14px | 16–18px | 12–16px |
| `touch` | 触屏或触控为主的混合设备 | 44px;Material 48dp | 44/48px | 44/48px | 14–16px | 18–20px | 16–20px |
- 紧凑桌面的常用操作不低于 28px;触屏命中区只给 `touch` profile,可见图形可以更小,扩展命中区互不重叠。
- Button、Input、Select 和相邻分段控件同高;图标按钮正方形;含图标按钮与纯文字按钮同高,文字与图标间距 6–8px。主 CTA 靠颜色、位置和层级突出,不靠加高。
- 密度由一套 token 或 variant 控制(`control-height`、`control-padding-x`、`icon-size`),全部组件共用。
- 同心圆角:`outer radius = inner radius + padding`;两层间距超过 24px 时视为独立表面,各自取值。
## 排版与间距
| 用途 | `compact` | `comfortable` |
|---|---:|---:|
| 正文 | 13.5–14px | 14–15px |
| 控件、菜单、条目标题 | 13px | 14px |
| 次要说明 | 12–13px | 12.5–13.5px |
| 非关键元信息 | 11.5–12px | 12px |
- 关键标签、状态和操作文字不小于 12px;控件嫌大时缩控件,字号不动。
- - 次要文字靠颜色降级,不靠 300 以下的细字重。CJK 小字号用更高行高并实机看。
+ - 次要文字靠颜色降级,不靠细字重。CJK 小字号用更高行高并实机看。
- 4px 间距尺度;2、6、10px 只用于图标或光学校准。相关内容紧,分组之间松。
- - 动态数字用 `tabular-nums`。
- 选字体、字阶、行高字距、换行截断与混合方向见 `reference/typography.md`。
## 图标
- Tab、分类、设置节标题、导航项、状态词配图标,让用户靠图形扫读;次要和行内操作(更多、删除、返回、停止、语言、复制)用 icon-only 按钮,配 accessible name 和 tooltip,文字按钮留给主操作与需要说清后果的确认。
- 功能图标单色(`currentColor`),颜色只表达状态或分类;品牌、平台、第三方产品名用官方 SVG,不手画。
- 图标不细不小:16px 槽位描边取 2,尺寸跟随相邻文字。细节见 `reference/icons.md`。
## 视觉层级
- - 先用间距和对齐分组(分割线规则见「其他模板痕迹」)。
- - Card 只包裹真正独立、可操作的对象,只有一层。去掉 border、阴影、背景、圆角后理解和操作不受影响的,就不该是 Card:设置组、表单段落、统计行、说明内容靠标题和间距分组,不上卡。
- - 普通 Card 用中性边界;状态或类别由 Badge、图标或文字表达。单侧彩色强调边只用于有提示语义的 Callout 或 Alert,颜色走共享语义 token。
+ - Card 只包裹真正独立、可操作的对象,边界用中性色。去掉 border、阴影、背景、圆角后理解和操作不受影响的,就不该是 Card:设置组、表单段落、统计行、说明内容靠标题和间距分组,不上卡。
- Tab 与分段控件:槽底加浮起的选中块,选中块在选项间滑动;全项目同一个实现。
- 浮层、可拖拽卡片这类"可抬起"的表面用 1px 半透明 ring 加柔阴影(`0 0 0 1px oklch(0 0 0 / .06), 0 4px 12px -2px oklch(0 0 0 / .08)`,暗色改单层 `0 0 0 1px oklch(1 0 0 / .08)`);静态内容卡不加阴影。`forced-colors: active` 会清掉 `box-shadow`,靠阴影表达边界的表面在该媒体查询里补 `border: 1px solid`。分割线、表格边界、输入框轮廓、选中态和 focus ring 保持真实 border。
- 图片需要边界时加 1px 纯中性描边(亮色 `oklch(0 0 0 / .1)`,暗色 `oklch(1 0 0 / .1)`);带色相的近黑叠在图片边缘像脏污。
- 弹层的关闭按钮与标题同一行(无标题时贴角),不单占一行空白;弹层尺寸随内容取,不撑满。
- 可滚动或折叠区域给出可见提示:露出下一项的一部分、边缘渐隐或计数。内部滚动区用 `scrollbar-width: thin` 和 `scrollbar-gutter: stable`,不用默认的粗滚动条。
- Sticky 操作只给高频、跨长列表仍需可见的动作,并让出内容、键盘焦点和小窗口视口。
## 空态与渐进披露
- 容器为空时,只对已有内容才有意义的控件(搜索、筛选、排序、计数、批量操作、依赖既有内容的次级入口)等内容出现后再渲染,位置与最终布局一致。整屏让给一个居中引导:一句状态 + 一句下一步 + 1(最多 2)个此刻就能完成的动作;此刻走不通的能力写成一句预告。
- 加载中留白,数据到达再决定空态或内容。失败态与空态分开,失败可重试。
- 空态文案说清"还没有"与"怎么开始",用中性色和常规图标。插画先用产品已有品牌图形;确需生成时按产品语气(gpt-image),统一光影与配色。呼吸、漂浮动效只在语气支持时用。
- 有合理缺省值的可选字段收进「添加 X(可选)」显式展开,展开后保持展开:双向折叠会把已填但非法的值藏起来。数量区间、格式要求等硬约束以紧凑形式常驻。
- 低频可选输入默认收成 icon-only 或一行入口,点开出输入框(autoFocus),失焦且为空时收回;有内容时保持展开。必填项常驻。placeholder 或禁用态提示已承担"下一步"时,空内容区留白。
## 文案
- 描述、提示、占位、Toast、按钮文案单句结尾不加句号。
- Button 与链接写具体动作或目的,脱离相邻正文仍能理解;上下文已唯一确定对象时省略对象名。
- 设置项名称写"打开后会发生什么",用肯定句;描述默认不写,需要时按「标签与页眉」收进问号。分区标题用平实名词,破坏性操作放在常规分区里用红色按钮,不起"危险区"这类标题。
- 中英文案保持语义、阈值和数量一致;只有措辞本身是需求时才用测试锁定。
- 界面不显示内部 ID、订单号原串、枚举名和错误码;要给用户留痕时收进「详情」或复制按钮,错误写成原因加下一步。
## 交互
- 每个交互组件实现适用的 default、hover、focus-visible、active、disabled、loading、error、success 状态。Web 自定义控件写 `cursor: pointer`(Tailwind v4 preflight 把 button 设回 `default`);原生桌面控件遵循平台行为。
- - 上传、删除、保存、发送点下去的瞬间进入进行中(行内 spinner 或进度),成功短暂着绿后回常态,失败行内标红并可重试;新增和移除的行有进出动效。不让用户对着空白等结果。
+ - 上传、删除、保存、发送点下去的瞬间进入进行中(行内 spinner 或进度,批量时按条目),成功短暂着绿后回常态,失败行内标红并可重试。不让用户对着空白等结果。
- 会变的数字、状态词和按钮文案,容器按最大形态预留尺寸(`tabular-nums`、固定宽或 `min-height`),变化不推动邻居;骨架与最终内容同尺寸。
- 点击当前 tab、当前选项等幂等目标,视图保持原样。
- 有选中项的列表打开时让当前项进入可视区,用 `aria-current`、`aria-selected` 表达状态。
- Chat、日志、时间线打开时跟随最新内容;用户离开底部后暂停,回到底部恢复。阈值由行高或 token 决定,用事件和 observer 驱动。
- 复制按钮只在复制是高频任务时常驻;否则在 hover、focus-within 或上下文菜单中出现,键盘可达。
- - 表单与反馈有三条发布门,请求冲突时说明依据并实施最接近原意的安全替代:认证、地址、付款和多字段表单保留持久可见 Label;错误、安全影响、不可逆后果和完成任务所需信息持久可见;Toggle 等已有明确终态的控件,终态即反馈。
## 动效
- 预算按触发频率分档:键盘驱动的重复操作(命令面板开合、快捷键、筛选重排)即时;容器进出(弹层、抽屉、Tab 面板、列表进详情、新增或删除的行)和选中指示的移动是常规操作,都有短进出;庆祝、重绘图标、成品动效件只给低频或首次体验。同一类容器全项目走同一套进出配方,不出现"旧会话有动效、新建没有"。
- 每个动效说得出用途:反馈、空间连续、状态变化、避免跳变、讲解。高频处"好看"不算用途。
- 方向表达空间关系:同级切换(Tab、分段)沿水平轴,方向跟随选项先后;进入详情向前、返回反向;浮层从触发点或边缘长出。
- - 位移、缩放和进出场只动 `transform`/`opacity`;可被快速重复触发的用 transition 或 spring(从当前值中断重定向),不用 keyframes。
- - 反馈 120–180ms,UI 动效不超过 300ms;标志性动效 280–700ms,只出现在少数低频、高意图组件。
+ - 位移、缩放和进出场只动 `transform`/`opacity`;可被快速重复触发的用 transition 或 spring(从当前值中断重定向),不用 keyframes(中断即从零重播)。
+ - 反馈 120–180ms,UI 动效不超过 300ms(整屏 Drawer、Sheet 至多 500ms);标志性动效 280–700ms,只出现在少数低频、高意图组件。
## 压测与完成标准
压测:用真实最坏数据,从数据入口替换而不改组件;定宽容器配 `min-width: 0` 和明确的换行或截断策略,截断后原文仍可获取:长名(`Aleksandra Wiśniewska-Kowalczyk`)、无空格长邮箱、单字名(`Jo`)、缺失的可选字段与头像、计数 0 / 1 / 1284、超长译文(德语复合词)、CJK、RTL、emoji 开头的名字、1000+ 行列表;在真实容器宽、320px、200% 缩放和暗色下看。常见签名:头像被挤成椭圆 → `flex-shrink: 0`;文字撑破容器 → 文本列 `min-width: 0`(grid 用 `minmax(0, 1fr)`);邮箱、URL 溢出 → `overflow-wrap: anywhere`;"1 members" → `Intl.PluralRules`;裸数字 → `Intl.NumberFormat`;文件名、路径、哈希末尾才有区别 → 中间截断;金额、日期等要比较的值不截断。
- 完成标准:
+ 完成标准,逐项核对本次改动触及的屏、组件与交互:
- 每屏的焦点已指认并做足。
- 「标签与页眉」「其他模板痕迹」已逐项对照目标界面。
- 同类组件的全部实例已列出并走同一个实现。
- 每个异步操作都看过进行中、成功、失败三态;每个渲染出的值都试过最坏值。
- 截图逐行看过:同一行的图标、文字、徽标、头像、右侧操作组沿交叉轴居中对齐。
- 密度 profile 落在 token 或共享组件上,而非逐处覆写。
- 动效已录屏或逐帧看过起点、终点、中途反向和 reduced-motion。
- 点击、切页、弹层与侧栏开合已用平台工具在真实数据量下测过响应:下一帧就有变化,过程中主线程没有超过一帧的长任务。截图和录屏看不出卡顿,方法见 `reference/motion.md`「检查动效」。
+ - 网页界面跑过 `bbu a11y <url>`(axe 无障碍审计),serious 与 critical 违规已修,修在颜色 token 或共享组件上。