| name | web-design-guidelines |
| description | 审查 UI 代码是否符合 Vercel Web Interface Guidelines 规范。触发词包括"审查我的 UI"、"检查可访问性"、"审计设计"、"审查 UX"、"检查站点最佳实践"。 |
| metadata | {"author":"vercel","version":"1.0.0","argument-hint":"<文件或模式>"} |
Web 界面指南
审查以下文件是否符合规范:$ARGUMENTS
读取文件,对照下方规则检查。输出简洁但全面——优先信息密度。高信噪比。
规则
可访问性
- 仅图标按钮需要
aria-label
- 表单控件需要
<label> 或 aria-label
- 交互元素需要键盘处理器(
onKeyDown/onKeyUp)
- 操作用
<button>,导航用 <a>/<Link>(不要用 <div onClick>)
- 图片需要
alt(装饰性图片用 alt="")
- 装饰性图标需要
aria-hidden="true"
- 异步更新(toast、验证)需要
aria-live="polite"
- 优先语义化 HTML(
<button>、<a>、<label>、<table>),再考虑 ARIA
- 标题层级有序
<h1>–<h6>;主要内容需跳转链接
- 标题锚点加
scroll-margin-top
Focus 状态
- 交互元素需要可见 focus:
focus-visible:ring-* 或等效样式
- 禁止
outline-none / outline: none,除非有替代 focus 样式
- 用
:focus-visible 而非 :focus(避免点击时出现 focus ring)
- 复合控件用
:focus-within 处理组内 focus
表单
- 输入框需要
autocomplete 和有意义的 name
- 使用正确的
type(email、tel、url、number)和 inputmode
- 禁止阻止粘贴(
onPaste + preventDefault)
- 标签可点击(
htmlFor 或包裹控件)
- 邮箱、验证码、用户名禁用拼写检查(
spellCheck={false})
- 复选框/单选:标签和控件共享点击区域(无死角)
- 提交按钮保持启用直到请求开始;请求期间显示 spinner
- 错误信息紧贴字段;提交时 focus 第一个错误
- 占位符以
… 结尾并展示示例格式
- 非认证字段用
autocomplete="off" 避免密码管理器干扰
- 未保存更改时警告导航离开(
beforeunload 或路由守卫)
动画
- 遵循
prefers-reduced-motion(提供简化版或禁用)
- 仅动画
transform/opacity(合成器友好)
- 禁止
transition: all——显式列出属性
- 设置正确的
transform-origin
- SVG:在
<g> wrapper 上做 transform,设置 transform-box: fill-box; transform-origin: center
- 动画可中断——中途响应用户输入
字体排版
- 用
… 而非 ...
- 弯引号
" " 而非直引号 "
- 不间断空格:
10 MB、⌘ K、品牌名
- 加载状态以
… 结尾:"Loading…"、"Saving…"
- 数字列/对比用
font-variant-numeric: tabular-nums
- 标题用
text-wrap: balance 或 text-pretty(防止孤行)
内容处理
- 文本容器处理超长内容:
truncate、line-clamp-* 或 break-words
- Flex 子元素需要
min-w-0 才能截断文本
- 处理空状态——空字符串/空数组不要渲染破损 UI
- 用户生成内容:预判短、平均、超长三种输入
图片
<img> 需显式 width 和 height(防止 CLS)
- 屏幕下方图片:
loading="lazy"
- 屏幕上方关键图片:
priority 或 fetchpriority="high"
性能
- 大列表(>50 条):虚拟化(
virtua、content-visibility: auto)
- 渲染期间禁止读取布局(
getBoundingClientRect、offsetHeight、offsetWidth、scrollTop)
- 批量 DOM 读/写;避免交错
- 优先非受控输入;受控输入每次按键必须开销低
- CDN/资源域名加
<link rel="preconnect">
- 关键字体:
<link rel="preload" as="font"> 配合 font-display: swap
导航与状态
- URL 反映状态——筛选器、标签页、分页、展开面板放在 query params
- 链接用
<a>/<Link>(支持 Cmd/Ctrl+点击、中键点击)
- 所有状态 UI 支持深度链接(用
useState 时考虑通过 nuqs 等同步 URL)
- 破坏性操作需确认弹窗或撤销窗口——禁止立即执行
触摸与交互
touch-action: manipulation(防止双击缩放延迟)
-webkit-tap-highlight-color 显式设置
- 弹窗/抽屉/面板用
overscroll-behavior: contain
- 拖拽时:禁用文本选择,拖拽元素加
inert
autoFocus 谨慎使用——仅桌面单一主要输入;移动端避免
Safe Areas 与布局
- 全出血布局需要
env(safe-area-inset-*) 处理刘海
- 防止意外滚动条:容器用
overflow-x-hidden,修复内容溢出
- 布局用 Flex/Grid,不用 JS 测量
深色模式与主题
- 深色主题
<html> 加 color-scheme: dark(修复滚动条、输入框样式)
<meta name="theme-color"> 与页面背景匹配
- 原生
<select>:显式 background-color 和 color(Windows 深色模式)
本地化与国际化
- 日期/时间:用
Intl.DateTimeFormat,不用硬编码格式
- 数字/货币:用
Intl.NumberFormat,不用硬编码格式
- 通过
Accept-Language / navigator.languages 检测语言,不用 IP
Hydration 安全
- 带
value 的输入框需要 onChange(或用 defaultValue 非受控)
- 日期/时间渲染:防止 hydration 不匹配(服务端 vs 客户端)
suppressHydrationWarning 仅在真正需要时使用
Hover 与交互状态
- 按钮/链接需要
hover: 状态(视觉反馈)
- 交互状态增强对比度:hover/active/focus 比默认态更醒目
内容与文案
- 主动语态:"安装 CLI"而非"CLI 将被安装"
- 标题/按钮用 Title Case(芝加哥风格)
- 数字表示数量:"8 次部署"而非"八次"
- 具体的按钮标签:"保存 API Key"而非"继续"
- 错误信息包含修复步骤,不只描述问题
- 第二人称;避免第一人称
- 空间受限时用
& 替代"和"
反模式(标记这些)
user-scalable=no 或 maximum-scale=1 禁用缩放
onPaste 配 preventDefault
transition: all
outline-none 无 focus-visible 替代
- 内联
onClick 导航而非 <a>
<div> 或 <span> 加点击处理器(应为 <button>)
- 图片无尺寸
- 大数组
.map() 无虚拟化
- 表单输入无标签
- 图标按钮无
aria-label
- 硬编码日期/数字格式(用
Intl.*)
autoFocus 无明确理由
输出格式
按文件分组。用 file:line 格式(VS Code 可点击)。简洁输出。
## src/Button.tsx
src/Button.tsx:42 - 图标按钮缺少 aria-label
src/Button.tsx:18 - 输入框缺少标签
src/Button.tsx:55 - 动画缺少 prefers-reduced-motion
src/Button.tsx:67 - transition: all → 显式列出属性
## src/Modal.tsx
src/Modal.tsx:12 - 缺少 overscroll-behavior: contain
src/Modal.tsx:34 - "..." → "…"
## src/Card.tsx
✓ pass
输出问题 + 位置。修复不明显时才解释。无前言。