关于 ui-design
面向 Agent 的前端界面设计规范 Skill,适用于使用 Tailwind CSS 构建或审查界面的开发者。它以明确约束覆盖无障碍、交互状态、动画、排版和布局。
主要功能
- 01规定 Tailwind CSS 默认值优先
- 02提供交互与无障碍要求
- 03约束动画属性与时长
- 04涵盖排版和布局规则
- 05检查加载、错误及空状态
适用场景
- 01构建 Tailwind CSS 界面组件
- 02审查前端无障碍与键盘交互
- 03设计动画、加载和错误状态
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ ckorhonen/ claude-skills --skill ui-design安装后在 Claude Code 中输入/ui-design确认已加载。
详细介绍
UI 设计
为使用 Agent 构建更出色的界面制定明确约束。
适用场景
- 使用 Tailwind CSS 构建 UI 组件
- 实现动画或过渡效果
- 添加带有键盘/焦点行为的交互元素
- 审查前端代码的无障碍性
- 设计具有适当 z-index 和间距的布局
- 处理加载状态、错误处理或空状态
技术栈
| 要求 | 规则 |
|---|---|
| Tailwind CSS | 必须优先使用默认值(间距、圆角、阴影),再使用自定义值 |
| 动画库 | 必须使用 motion/react(原名 framer-motion)实现 JS 动画 |
| CSS 动画 | 应使用 tw-animate-css 实现进入动画和微动画 |
| 类名逻辑 | 必须使用 cn 工具(clsx + tailwind-merge) |
组件
| 要求 | 规则 |
|---|---|
| 交互式基础组件 | 必须使用无障碍基础组件(Base UI、React Aria、Radix)处理键盘/焦点行为 |
| 现有组件 | 必须优先使用项目现有的基础组件 |
| 一致性 | 绝不能在同一个交互区域内混用不同的基础组件系统 |
| 新基础组件 | 如果与技术栈兼容,应优先选择 Base UI |
| 图标按钮 | 仅含图标的按钮必须添加 aria-label |
| 自定义行为 | 除非明确要求,否则绝不能手动重建键盘或焦点行为 |
交互
| 要求 | 规则 |
|---|---|
| 破坏性操作 | 破坏性或不可逆操作必须使用 AlertDialog |
| 加载状态 | 应使用结构化骨架屏 |
| 视口高度 | 绝不能使用 h-screen,应使用 h-dvh |
| 固定元素 | 必须遵循 safe-area-inset |
| 错误显示 | 必须在操作发生位置附近显示错误 |
| 输入行为 | 绝不能阻止在 input 或 textarea 元素中粘贴 |
动画
| 要求 | 规则 |
|---|---|
| 默认 | 除非明确要求,否则绝不能添加动画 |
| 合成器属性 | 只能对 transform、opacity 添加动画 |
| 布局属性 | 绝不能对 width、height、top、left、margin、padding 添加动画 |
| 绘制属性 | 应避免对 background、color 添加动画,小范围局部 UI(文本、图标)除外 |
| 进入缓动 | 进入动画应使用 ease-out |
| 反馈时长 | 交互反馈绝不能超过 200ms |
| 循环动画 | 循环动画移出视口时必须暂停 |
| 无障碍性 | 必须遵循 prefers-reduced-motion |
| 自定义缓动 | 除非明确要求,否则绝不能引入自定义缓动曲线 |
| 大型界面 | 应避免对大图或全屏界面添加动画 |
排版
| 要求 | 规则 |
|---|---|
| 标题 | 必须使用 text-balance |
| 正文文本 | 段落必须使用 text-pretty |
| 数据 | 必须使用 tabular-nums |
| 密集型 UI | 应使用 truncate 或 line-clamp |
| 字间距 | 除非明确要求,否则绝不能修改 letter-spacing(tracking-) |
布局
| 要求 | 规则 |
|---|---|
| Z-index | 必须使用固定刻度(不能使用任意 z-x) |
| 正方形元素 | 应使用 size-x,而不是 w-x + h-x |
性能
| 要求 | 规则 |
|---|---|
| 模糊效果 | 绝不能对大范围 blur() 或 backdrop-filter 界面添加动画 |
| Will-change | 绝不能在动画进行期间以外应用 will-change |
| useEffect | 绝不能用于可通过渲染逻辑实现的内容 |
设计
| 要求 | 规则 |
|---|---|
| 渐变 | 除非明确要求,否则绝不能使用 |
| 紫色/多色渐变 | 绝不能使用 |
| 发光效果 | 绝不能将其用作主要提示 |
| 阴影 | 除非明确要求,否则应使用 Tailwind CSS 默认刻度 |
| 空状态 | 必须提供一个明确的下一步操作 |
| 强调色 | 每个视图应限制使用一种 |
| 颜色令牌 | 引入新令牌前,应优先使用现有主题或 Tailwind CSS 令牌 |
常见陷阱
最常见的 UI 设计问题出现在间距、颜色对比度、移动端适配、状态管理和视觉层次方面。这些问题是在 Agent 构建界面时反复犯错后总结出来的。
1. 间距不一致(边距随意,没有规范)
问题: 混用各种 Tailwind 间距值,且没有明确的规范,会让布局显得杂乱无章。
// ❌ WRONG - arbitrary pixel values, no spacing system
<div className="ml-[13px] mr-[22px] pt-[7px]">Content</div>
// ✅ CORRECT - use system scales
<div className="ml-4 mr-4 pt-4">Content</div>
为什么会失败:
- 设计看起来像是随意拼凑的(有些间距是
2px,有些是16px,毫无规律) - 移动端布局会出问题(间距无法按比例缩放)
- 无法对齐(间隙无法与网格对齐)
解决方法:
- 始终使用 Tailwind 间距比例(
0、1、2、3、4、6、8、12、16、24、32等) - 为常见模式定义间距规范:
- 按钮内边距:
px-4 py-2 - 卡片内边距:
p-6 - 区块之间的间隙:
gap-8 - 嵌套间距:
ml-6(而不是ml-3)
- 按钮内边距:
- 为相关元素分组,并保持间隙一致(所有水平列表使用相同的
gap-x)
2. 颜色对比度不足(违反无障碍要求)
问题: 颜色组合未达到 WCAG AA 对比度比例(文本为 4.5:1,UI 组件为 3:1),导致视力较弱的用户难以阅读内容。
// ❌ WRONG - gray-400 text on gray-100 background fails contrast
<p className="text-gray-400 bg-gray-100">Important content</p>
// ✅ CORRECT - gray-700 on gray-100 passes WCAG AA
<p className="text-gray-700 bg-gray-100">Important content</p>
为什么会失败:
- 约 4-5% 的用户有色盲,而更广泛的群体中,超过 15% 的人存在某种视力障碍
- 使用高亮度屏幕(如手机)的用户无法阅读对比度较低的文本
- 存在法律责任风险(许多司法管辖区要求符合 WCAG 标准)
解决方法:
- 使用对比度足够的颜色组合:
- 在任何背景上使用
text-gray-900/text-white(始终安全) - 在浅色背景上使用
text-gray-700 - 在深色背景上使用
text-gray-300
- 在任何背景上使用
- 测试颜色: 使用在线对比度检查工具(https://webaim.org/resources/contrastchecker/)
- 避免有问题的组合:
gray-400配gray-100❌red-500配pink-100❌- 禁用状态:白色背景上使用
text-gray-400,彩色背景上使用text-gray-600
- 彩色文本(非灰色): 使用较深的色调(
red-700,而非red-300)
3. 不适合移动端的布局(触控目标过小、横向滚动)
问题: 触控目标小于 44×44px、需要横向滚动,或布局无法适配较窄的视口。
// ❌ WRONG - button too small, no responsive layout
<button className="px-2 py-1 text-xs">Click me</button>
<div className="flex gap-2">
<div className="w-80">Sidebar</div>
<div className="w-80">Content</div>
</div>
// ✅ CORRECT - hit target size, responsive stack
<button className="px-4 py-3 md:px-6 md:py-3">Click me</button>
<div className="flex flex-col md:flex-row gap-4">
<div className="w-full md:w-80">Sidebar</div>
<div className="flex-1">Content</div>
</div>
为什么会失败:
- 40% 的流量来自移动端;按钮太小会难以点击
- 在手机上横向滚动会严重影响用户体验
- 在桌面端可用的布局,在移动端可能完全无法使用
解决方法:
- 触控目标最小尺寸:44×44px
- 按钮:至少使用
px-4 py-3(标准值:px-6 py-3) - 链接:将链接放入更大的可点击区域中
- 按钮:至少使用
- 在移动端改为纵向排列: 默认使用
flex-col,桌面端使用md:flex-row - 使用响应式宽度:
- 移动端使用
w-full,桌面端使用md:w-80或md:w-1/3 - 灵活布局中使用
flex-1,而非固定宽度
- 移动端使用
- 测试响应式效果: 检查 375px(iPhone SE)和 768px(平板)的断点
- 避免横向滚动: 绝不要让用户横向滚动
4. 状态缺失(加载、错误、空内容、禁用)
问题: 界面只显示顺利完成时的情况,在加载、出错或内容为空时会无声失败。
// ❌ WRONG - no feedback states
<button onClick={save}>Save</button>
<div>{data.map(item => <ItemCard item={item} />)}</div>
// ✅ CORRECT - all states accounted for
<button onClick={save} disabled={loading}>
{loading ? 'Saving...' : 'Save'}
</button>
{loading && <LoadingSkeleton />}
{error && <ErrorAlert message={error} />}
{!loading && data.length === 0 && <EmptyState action="Create your first item" />}
{!loading && !error && data.map(item => <ItemCard item={item} />)}
为什么会失败:
- 用户不知道操作是否成功(没有反馈就会让人觉得操作失败了)
- 空列表看起来像是出了问题,而非有意为空
- 出错后没有恢复途径
解决方法:
- 加载状态: 使用结构化骨架屏(而非旋转加载图标)
- 内容加载期间保持布局稳定
- 让用户看到即将显示的内容,而不只是加载动画
- 错误状态: 在失败的操作旁显示
- 说明发生了什么以及如何解决
- 提供重试按钮
- 空状态: 明确呈现,并提供可执行操作
- “还没有项目” → “创建你的第一个项目”(按钮)
- 说明空状态的含义,以及如何添加内容
- 禁用状态: 始终提供视觉反馈
disabled={true}+opacity-50或cursor-not-allowed- 绝不要在不说明原因的情况下直接禁用
5. 层级不清(所有内容看起来同等重要)
问题: 所有文本大小相同、颜色权重相同、间距相同——没有任何内容突出显示。
// ❌ WRONG - flat hierarchy
<div className="text-lg text-gray-700">
<div className="text-lg text-gray-700">Subheading</div>
<div className="text-lg text-gray-700">Subtitle</div>
<button className="text-lg px-4 py-2">Action</button>
</div>
// ✅ CORRECT - clear hierarchy
<div>
<h1 className="text-3xl font-bold text-gray-900">Title</h1>
<h2 className="text-xl font-semibold text-gray-700 mt-6">Subheading</h2>
<p className="text-base text-gray-600 mt-2">Subtitle</p>
<button className="mt-6 px-6 py-3 bg-blue-600 text-white font-semibold rounded">
Primary Action
</button>
</div>
为什么会失败:
- 用户不知道应该先看哪里
- 浏览页面的速度更慢(缺乏便于快速浏览的结构)
- 重要操作容易被忽略
修复方法:
- 大小层级:
- 标题:
text-3xl(h1) →text-2xl(h2) →text-xl(h3) - 正文:
text-base(段落)→text-sm(次要内容)
- 标题:
- 字重层级:
- 主要操作:
font-bold或font-semibold - 重要文本:
font-semibold - 正文:
font-normal - 次要内容:
font-normal,并使用较浅的颜色
- 主要操作:
- 颜色层级:
- 主要文本:
text-gray-900 - 次要文本:
text-gray-600 - 第三级文本:
text-gray-500
- 主要文本:
- 间距层级:
- 区块间距:
gap-8(最大) - 组件间距:
gap-4 - 密集内容:
gap-2
- 区块间距:
- 每个视图使用一种强调色: CTA 使用单一颜色,不要使用多种颜色争夺注意力
快速参考
允许的动画属性
transform, opacity
禁止的动画属性
width, height, top, left, margin, padding, blur(), backdrop-filter
必需的无障碍模式
// Icon button - always add aria-label
<button aria-label="Close dialog">
<XIcon />
</button>
// Respect reduced motion
@media (prefers-reduced-motion: reduce) {
* { animation: none !important; }
}
类名实用工具模式
import { clsx } from 'clsx';
import { twMerge } from 'tailwind-merge';
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
评论
支持 Markdown