设计工程原则,让界面感觉更精致。在构建UI组件、审查前端代码、实现动画、悬停状态、阴影、边框、微交互、进入/退出动画、选择或审查图标,或任何视觉细节工作时使用。触发条件:UI打磨、设计细节、“让它感觉更好”、“感觉不对劲”、交错动画、边框半径、光学对齐、图像轮廓、盒阴影、图标、图标描边粗细、图标状态、动效克制。
让界面感觉更好的细节
优秀的界面很少来自单一因素。通常是许多小细节的累积,共同构成出色的体验。在构建或审查UI代码时应用这些原则。
审查时,放慢界面速度:在浏览器的动画面板中以10%速度重放动画,并遍历每个状态:悬停、聚焦、激活、加载、空状态。在10%速度下感觉不对劲的地方,就是全速时微妙出错的地方。
保留项目的组件库、标记和密度。匹配其已建立的动效语言,除非以下原则规定了精确的交互模式。
排版(文本换行、字体渲染、表格数字、间距)由 better-typography 技能覆盖;文本相关事项请使用该技能。可访问性(点击区域、聚焦状态、键盘支持、ARIA、减少动效)由 better-accessibility 技能覆盖。布局结构(分组、区块间间距、断点、空间RTL)由 better-layout 技能覆盖。
快速参考
| 类别 | 使用场景 |
|---|---|
| 表面 | 边框半径、光学对齐、阴影、图像轮廓 |
| 动画 | 可中断动画、进入/退出过渡、图标动画、按压缩放、动效克制 |
| 图标 | 图标描边粗细、通过 currentColor 的状态、轮廓与填充、尺寸、RTL翻转 |
| 性能 | 过渡属性指定、will-change 的使用 |
核心原则
1. 同心边框半径
外半径 = 内半径 + 内边距。嵌套元素半径不匹配是让界面感觉不对劲的最常见原因。
2. 光学对齐优先于几何对齐
当几何居中看起来不对时,进行光学对齐。带图标的按钮、播放三角形和不对称图标都需要手动调整。
3. 阴影用于层次,边框用于结构
对于按钮、卡片和容器,如果边框仅用于制造深度,优先使用多层透明 box-shadow 值。保留用于传达结构或状态的边框:分隔线、布局分隔符以及选中或聚焦状态。
4. 可中断动画
对交互状态变化使用CSS过渡:它们可以在动画中途被中断。将关键帧保留给一次性执行的阶段性序列。
5. 拆分并交错进入动画
对于不频繁的阶段性进入,且顺序有助于传达层次时,将内容拆分为语义块,并交错约100毫秒,而不是动画化单个容器。不要对常规、高频交互进行交错。
6. 微妙的退出动画
使用小的固定 translateY 而不是完整高度。退出应比进入更柔和。进入和退出过渡都使用 ease-out。
7. 上下文相关的图标动画
使用 opacity、scale 和 blur 动画化图标,而不是切换可见性。精确使用这些值:缩放从 0.25 到 1,透明度从 0 到 1,模糊从 4px 到 0px。如果项目在 package.json 中有 motion 或 framer-motion,匹配该包的导入路径(或两者都存在时使用已建立的附近导入),并使用 transition: { type: "spring", duration: 0.3, bounce: 0 };bounce 必须始终为 0。如果没有安装动效库,将两个图标都保留在DOM中(一个绝对定位),并使用CSS过渡交叉淡入淡出,使用 cubic-bezier(0.2, 0, 0, 1);这样无需任何依赖即可实现进入和退出动画。
8. 图像轮廓
为图像添加微妙的 1px 低透明度轮廓,以保持一致的深度。颜色在浅色模式下必须是纯黑色(oklch(0 0 0 / 0.1)),在深色模式下必须是纯白色(oklch(1 0 0 / 0.1)),绝不能使用接近黑色的颜色,如石板色、锌色或任何带色调的中性色。带色调的轮廓会吸收其下方的表面颜色,在图像边缘看起来像污垢。
9. 按压缩放
点击时微妙的 scale(0.96) 为按钮提供触觉反馈。始终使用 0.96。切勿使用小于 0.95 的值:任何低于此的值都会感觉夸张。添加 static 属性以在动效会分散注意力时禁用它。
10. 页面加载时跳过动画
在 AnimatePresence 上使用 initial={false} 以防止首次渲染时的进入动画。验证它不会破坏有意的进入动画。
11. 绝不使用 transition: all
始终指定精确属性:transition-property: scale, opacity。Tailwind 的 transition-transform 覆盖 transform, translate, scale, rotate。
12. 谨慎使用 will-change
仅用于 transform、opacity、filter,这些是GPU可以合成的属性。绝不使用 will-change: all。仅在注意到首帧卡顿时添加。
13. 图标描边与文本粗细匹配
文本旁边的图标承载文本的光学重量:1.5px 描边对应常规(400)文本,2px 对应半粗(600)。每个图标集使用一种描边粗细;切勿在同一表面混合使用不同库。
14. 一个SVG,按状态重新着色
图标使用 currentColor,其状态(悬停、选中、禁用)通过CSS颜色和透明度实现,绝不使用单独的素材。轮廓变体为默认,填充变体标记激活状态。
15. 动效克制
高频交互上不要使用自定义动画:每次触发都会重复注意力成本。动效绝不是唯一的反馈渠道;每个动画状态变化还需要一个静态提示(颜色、图标、标签)。
常见错误
| 错误 | 修复 |
|---|---|
| 紧密嵌套的父元素和子元素使用相同的边框半径 | 计算 outerRadius = innerRadius + padding |
| 图标看起来不居中 | 通过内边距或直接修复SVG进行光学调整 |
| 仅用于伪造层次的边框 | 使用带透明度的分层 box-shadow;保留结构性和状态边框 |
| 突兀的阶段性进入或上下文退出 | 交错不频繁的进入,并保持保留上下文的退出微妙 |
| 有状态的图标或切换在页面加载时动画化其默认状态 | 向该 AnimatePresence 添加 initial={false};保留有意的页面进入 |
元素上的 transition: all |
指定精确属性 |
| 首帧动画卡顿 | 添加 will-change: transform(谨慎使用) |
| 粗体文本旁的极细图标 | 将描边宽度与文本粗细匹配 |
| 每个状态使用单独的图标素材 | 一个 currentColor SVG,状态通过CSS实现 |
| 到处使用填充图标 | 轮廓为默认,仅激活状态使用填充 |
| 每次悬停或按键时都有进入动画 | 即时反馈或≤150ms的透明度/颜色过渡 |
审查输出格式
仅当用户要求独立的UI打磨审查时使用此格式。当 better-interface 协调审查时,向该技能提供领域证据和发现,并让其输出格式、严重性等级、合并规则、上限和结论优先。
以两部分呈现独立审查。
发现
按原则分组所有确认的发现。使用带有严重性、位置、之前、之后和原因列的Markdown表格。绝不使用单独的“之前:”/“之后:”行。
- 严重性:
HIGH使交互误导、无响应或反复干扰;MEDIUM造成明显的工艺或一致性问题;LOW是孤立的打磨问题。 - 位置:引用
path/to/file:line。如果工件没有源文件,引用确切的屏幕和组件。 - 之前/之后:显示当前实现和可操作的替换方案。
- 原因:指出违反的原则并解释它如何影响界面。
将重复的系统性问题合并为一行,并列出每个受影响的位置。省略没有发现的原理。
示例
同心边框半径
| 严重性 | 位置 | 之前 | 之后 | 原因 |
|---|---|---|---|---|
| LOW | src/Card.tsx:28 |
卡片 rounded-xl + 内部按钮 rounded-xl(p-2) |
卡片 rounded-2xl(8 + 8 = 16),内部按钮 rounded-lg |
嵌套角应为同心 |
| LOW | src/card.css:11 |
两个嵌套表面均为 border-radius: 16px |
外部 24px,内部 16px,内边距 8px |
相等的嵌套半径使内部表面看起来被挤压 |
按压缩放
| 严重性 | 位置 | 之前 | 之后 | 原因 |
|---|---|---|---|---|
| LOW | src/Button.tsx:19 |
<button className="..."> |
添加 active:scale-[0.96] transition-transform |
按压反馈使控件感觉响应灵敏 |
| MEDIUM | src/button.css:24 |
按压时 scale(0.9) |
提高到 scale(0.96) |
任何低于 0.95 的值都会感觉夸张 |
验证与结论
在发现之后:
- 验证:列出执行的确切检查及其观察结果。遍历每个相关状态,并在涉及动画时以10%速度检查动效。如果某项检查未执行,说明仍需验证的内容。
- 结论:如果存在任何
HIGH发现,则为Block;如果仅存在MEDIUM或LOW发现,则为Needs changes;仅当没有可操作的发现时,才为Approve。
当没有发现时,省略表格,说明“无可操作的UI打磨发现”,报告验证,并以 Approve 结束。






