frontend-patterns
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseFrontend Patterns
前端开发模式
Overview
概述
User interfaces exist to help users accomplish tasks. Every UI decision should make the user's task easier or the interface more accessible.
Core principle: Design for user success, not aesthetic preference.
Violating the letter of this process is violating the spirit of frontend design.
用户界面的存在是为了帮助用户完成任务。每一项UI决策都应让用户的任务更简单,或让界面更易于访问。
核心原则: 以用户成功为设计目标,而非审美偏好。
违反这一流程的字面要求,就是违背前端设计的核心精神。
Focus Areas (Reference Pattern)
重点领域(参考模式)
- React component architecture (hooks, context, performance)
- Responsive CSS with Tailwind/CSS-in-JS
- State management (Redux, Zustand, Context API)
- Frontend performance (lazy loading, code splitting, memoization)
- Accessibility (WCAG compliance, ARIA labels, keyboard navigation)
- React组件架构(hooks、context、性能优化)
- 基于Tailwind/CSS-in-JS的响应式CSS
- 状态管理(Redux、Zustand、Context API)
- 前端性能优化(懒加载、代码分割、记忆化)
- 无障碍设计(WCAG合规、ARIA标签、键盘导航)
Approach (Reference Pattern)
实施方法(参考模式)
- Component-first thinking - reusable, composable UI pieces
- Mobile-first responsive design - start small, scale up
- Performance budgets - aim for sub-3s load times
- Semantic HTML and proper ARIA attributes
- Type safety with TypeScript when applicable
- 组件优先思维 - 可复用、可组合的UI组件
- 移动端优先的响应式设计 - 从小屏布局开始,逐步扩展到大屏
- 性能预算 - 目标加载时间控制在3秒以内
- 语义化HTML与正确的ARIA属性
- 适用场景下使用TypeScript保证类型安全
Component Output Checklist
组件交付检查清单
Every frontend deliverable should include:
- Complete React component with props interface
- Styling solution (Tailwind classes or styled-components)
- State management implementation if needed
- Basic unit test structure
- Accessibility checklist for the component
- Performance considerations and optimizations
Focus on working code over explanations. Include usage examples in comments.
所有前端交付物必须包含:
- 完整的React组件及Props接口定义
- 样式实现方案(Tailwind类或styled-components)
- 必要的状态管理实现
- 基础单元测试结构
- 组件无障碍设计检查清单
- 性能考量与优化措施
优先保证可运行代码,而非文字说明。在注释中包含使用示例。
The Iron Law
铁律
NO UI DESIGN BEFORE USER FLOW IS UNDERSTOODIf you haven't mapped what the user is trying to accomplish, you cannot design UI.
NO UI DESIGN BEFORE USER FLOW IS UNDERSTOOD若未梳理清楚用户的目标流程,则无法进行UI设计。
Design Thinking (Pre-Code)
设计思维(编码前)
Before writing any UI code, commit to answers for:
- Purpose: What specific problem does this interface solve?
- Tone: Choose an aesthetic direction and commit to it:
- Brutally minimal, maximalist, retro-futuristic, organic/natural
- Luxury/refined, playful/toy-like, editorial/magazine, brutalist/raw
- Art deco/geometric, soft/pastel, industrial/utilitarian
- Constraints: Framework requirements, performance budget, accessibility level
- Differentiation: What's the ONE thing someone will remember about this UI?
Key insight: Bold maximalism and refined minimalism both work. The enemy is indecision and generic defaults.
在编写任何UI代码前,必须明确以下问题的答案:
- 目的:该界面要解决什么具体问题?
- 风格基调:选定一种美学方向并坚持执行:
- 极简主义、极繁主义、复古未来主义、有机自然风
- 奢华精致风、趣味玩具风、杂志编辑风、粗粝原始风
- 装饰艺术几何风、柔和马卡龙风、工业实用风
- 约束条件:框架要求、性能预算、无障碍等级
- 差异化:用户对该UI最深刻的记忆点是什么?
核心见解: 大胆的极繁主义与精致的极简主义都能奏效。大忌是优柔寡断和使用通用默认样式。
Loading State Order (CRITICAL)
加载状态顺序(至关重要)
Always handle states in this order:
typescript
// CORRECT order
if (error) return <ErrorState error={error} onRetry={refetch} />;
if (loading && !data) return <LoadingState />;
if (!data?.items.length) return <EmptyState />;
return <ItemList items={data.items} />;Loading State Decision Tree:
Is there an error? → Yes: Show error with retry
→ No: Continue
Is loading AND no data? → Yes: Show loading indicator
→ No: Continue
Do we have data? → Yes, with items: Show data
→ Yes, but empty: Show empty state
→ No: Show loading (fallback)Golden Rule: Show loading indicator ONLY when there's no data to display.
必须按以下顺序处理状态:
typescript
// 正确顺序
if (error) return <ErrorState error={error} onRetry={refetch} />;
if (loading && !data) return <LoadingState />;
if (!data?.items.length) return <EmptyState />;
return <ItemList items={data.items} />;加载状态决策树:
是否存在错误? → 是:显示带重试按钮的错误状态
→ 否:继续
是否处于加载状态且无数据? → 是:显示加载指示器
→ 否:继续
是否有数据? → 是且有内容:展示数据
→ 是但为空:展示空状态
→ 否:展示加载状态(兜底)黄金法则: 仅当无数据可展示时,才显示加载指示器。
Skeleton vs Spinner
骨架屏 vs 加载动画
| Use Skeleton When | Use Spinner When |
|---|---|
| Known content shape | Unknown content shape |
| List/card layouts | Modal actions |
| Initial page load | Button submissions |
| Content placeholders | Inline operations |
| 使用骨架屏的场景 | 使用加载动画的场景 |
|---|---|
| 已知内容形状 | 未知内容形状 |
| 列表/卡片布局 | 弹窗操作 |
| 初始页面加载 | 按钮提交 |
| 内容占位符 | 内联操作 |
Motion & Animation
动效与动画
| Rule | Do | Don't |
|---|---|---|
| Reduced motion | Honor | Ignore user preferences |
| Properties | Animate | Animate |
| Transitions | List properties explicitly | Use |
| Duration | 150-300ms for micro-interactions | Too fast (<100ms) or slow (>500ms) |
| Interruptible | Allow animation cancellation | Lock UI during animation |
css
/* CORRECT: Compositor-friendly, respects preferences */
@media (prefers-reduced-motion: no-preference) {
.card { transition: transform 200ms ease-out, opacity 200ms ease-out; }
.card:hover { transform: translateY(-2px); opacity: 0.95; }
}| 规则 | 正确做法 | 错误做法 |
|---|---|---|
| 减少动效 | 尊重 | 忽略用户偏好 |
| 动画属性 | 仅对 | 对 |
| 过渡效果 | 明确列出过渡属性 | 使用 |
| 时长 | 微交互使用150-300ms | 过快(<100ms)或过慢(>500ms) |
| 可中断性 | 允许取消动画 | 动画期间锁定UI |
css
/* 正确示例: compositor友好,尊重用户偏好 */
@media (prefers-reduced-motion: no-preference) {
.card { transition: transform 200ms ease-out, opacity 200ms ease-out; }
.card:hover { transform: translateY(-2px); opacity: 0.95; }
}Error Handling Hierarchy
错误处理层级
| Level | Use For |
|---|---|
| Inline error | Field-level validation |
| Toast notification | Recoverable errors, user can retry |
| Error banner | Page-level errors, data still partially usable |
| Full error screen | Unrecoverable, needs user action |
| 层级 | 适用场景 |
|---|---|
| 内联错误 | 字段级验证 |
| Toast通知 | 可恢复错误,用户可重试 |
| 错误横幅 | 页面级错误,数据仍可部分使用 |
| 全屏错误页 | 不可恢复错误,需要用户操作 |
Success Criteria Framework
成功标准框架
Every UI must have explicit success criteria:
- Task completion: Can user complete their goal?
- Error recovery: Can user recover from mistakes?
- Accessibility: Can all users access it?
- Performance: Does it feel responsive?
每个UI必须具备明确的成功标准:
- 任务完成度:用户能否完成目标?
- 错误恢复能力:用户能否从错误中恢复?
- 无障碍性:所有用户能否访问该界面?
- 性能表现:界面是否响应迅速?
Typography Rules
排版规则
| Rule | Correct | Wrong |
|---|---|---|
| Ellipsis | | |
| Quotes | | |
| Units | | |
| Shortcuts | | |
| Loading text | | |
| Numbers in tables | | Default proportional |
| Headings | | Unbalanced line breaks |
| Line length | 65-75 characters max | Unlimited width |
| 规则 | 正确示例 | 错误示例 |
|---|---|---|
| 省略号 | | |
| 引号 | | |
| 单位 | | |
| 快捷键 | | |
| 加载文本 | | |
| 表格中的数字 | | 默认比例数字 |
| 标题 | | 不平衡的换行 |
| 行长度 | 最多65-75个字符 | 无限制宽度 |
Content Overflow Handling
内容溢出处理
Prevent broken layouts from user-generated content:
| Scenario | Solution |
|---|---|
| Single-line overflow | |
| Multi-line overflow | |
| Long words/URLs | |
| Flex child truncation | Add |
| Empty strings/arrays | Show placeholder, not broken UI |
tsx
{/* Flex truncation pattern - min-w-0 is REQUIRED */}
<div className="flex items-center gap-2 min-w-0">
<Avatar />
<span className="truncate min-w-0">{user.name}</span>
</div>Test with: short text, average text, and absurdly long text (50+ characters).
防止用户生成的内容导致布局破裂:
| 场景 | 解决方案 |
|---|---|
| 单行溢出 | |
| 多行溢出 | |
| 长单词/URL | |
| Flex子元素截断 | 为Flex子元素添加 |
| 空字符串/数组 | 显示占位符,而非破裂的UI |
tsx
{/* Flex截断模式 - min-w-0是必须的 */}
<div className="flex items-center gap-2 min-w-0">
<Avatar />
<span className="truncate min-w-0">{user.name}</span>
</div>测试用例: 短文本、普通文本、超长文本(50+字符)。
Universal Questions (Answer First)
通用问题(必须先回答)
ALWAYS answer before designing/reviewing:
- What is the user trying to accomplish? - Specific task, not feature
- What are the steps? - Click by click
- What can go wrong? - Every error state
- Who might struggle? - Accessibility needs
- What's the existing pattern? - Project conventions
设计/评审前必须明确:
- 用户的目标是什么? - 具体任务,而非功能
- 步骤有哪些? - 逐点击流程
- 可能出现哪些问题? - 所有错误状态
- 哪些用户可能遇到困难? - 无障碍需求
- 现有模式是什么? - 项目约定
User Flow First
用户流程优先
Before any UI work, map the flow:
User Flow: Create Account
1. User lands on signup page
2. User enters email
3. User enters password
4. User confirms password
5. System validates inputs (inline)
6. User clicks submit
7. System processes (loading state)
8. Success: User sees confirmation + redirect
9. Error: User sees error + can retryFor each step, identify:
- What user sees
- What user does
- What feedback they get
- What can go wrong
在任何UI工作前,先梳理流程:
用户流程:创建账户
1. 用户进入注册页面
2. 用户输入邮箱
3. 用户输入密码
4. 用户确认密码
5. 系统验证输入(内联验证)
6. 用户点击提交
7. 系统处理请求(加载状态)
8. 成功:用户看到确认信息并跳转
9. 错误:用户看到错误信息并可重试针对每个步骤,明确:
- 用户看到什么
- 用户做什么
- 用户得到什么反馈
- 可能出现什么问题
UX Review Checklist
UX评审检查清单
| Check | Criteria | Example Issue |
|---|---|---|
| Task completion | Can user complete goal? | Button doesn't work |
| Discoverability | Can user find what they need? | Hidden navigation |
| Feedback | Does user know what's happening? | No loading state |
| Error handling | Can user recover from errors? | No error message |
| Efficiency | Can user complete task quickly? | Too many steps |
Severity levels:
- BLOCKS: User cannot complete task
- IMPAIRS: User can complete but with difficulty
- MINOR: Small friction, not blocking
| 检查项 | 标准 | 示例问题 |
|---|---|---|
| 任务完成度 | 用户能否完成目标? | 按钮无法点击 |
| 可发现性 | 用户能否找到所需功能? | 隐藏的导航 |
| 反馈机制 | 用户能否知晓当前状态? | 无加载状态 |
| 错误处理 | 用户能否从错误中恢复? | 无错误提示 |
| 效率 | 用户能否快速完成任务? | 步骤过多 |
严重等级:
- 阻塞:用户无法完成任务
- 影响:用户可完成但存在困难
- 轻微:小摩擦,不阻塞任务
Accessibility Review Checklist (WCAG 2.1 AA)
无障碍评审检查清单(WCAG 2.1 AA)
| Check | Criterion | How to Verify |
|---|---|---|
| Keyboard | All interactive elements keyboard accessible | Tab through entire flow |
| Focus visible | Current focus clearly visible | Tab and check highlight |
| Focus order | Logical tab order | Tab matches visual order |
| Labels | All inputs have labels | Check |
| Alt text | Images have meaningful alt | Check |
| Color contrast | 4.5:1 for text, 3:1 for large | Use contrast checker |
| Color alone | Info not conveyed by color only | Check without color |
| Screen reader | Content accessible via SR | Test with VoiceOver/NVDA |
For each issue found:
markdown
- [WCAG 2.1 1.4.3] Color contrast at `component:line`
- Current: 3.2:1 (fails AA)
- Required: 4.5:1
- Fix: Change text color to #333 (7.1:1)| 检查项 | 标准 | 验证方法 |
|---|---|---|
| 键盘导航 | 所有交互元素支持键盘访问 | 按Tab键遍历整个流程 |
| 焦点可见性 | 当前焦点清晰可见 | 按Tab键检查高亮效果 |
| 焦点顺序 | 合理的Tab顺序 | Tab顺序与视觉顺序一致 |
| 标签 | 所有输入框均有标签 | 检查 |
| 替代文本 | 图片有意义的alt文本 | 检查 |
| 颜色对比度 | 文本4.5:1,大文本3:1 | 使用对比度检查工具 |
| 仅用颜色传递信息 | 信息不能仅通过颜色传递 | 移除颜色后检查 |
| 屏幕阅读器 | 内容可通过屏幕阅读器访问 | 使用VoiceOver/NVDA测试 |
针对发现的每个问题:
markdown
- [WCAG 2.1 1.4.3] 颜色对比度问题位于 `component:line`
- 当前值:3.2:1(不满足AA标准)
- 要求值:4.5:1
- 修复方案:将文本颜色改为#333(对比度7.1:1)Form Best Practices
表单最佳实践
| Rule | Implementation |
|---|---|
| Autocomplete | Add |
| Input types | Use |
| Input modes | Add |
| Never block paste | No |
| Spellcheck off | |
| Unsaved changes | Warn before navigation ( |
| Error focus | Focus first error field on submit |
| Shared hit targets | Checkbox/radio label + control = one clickable area |
tsx
<input
type="email"
autoComplete="email"
spellCheck={false}
inputMode="email"
// Never: onPaste={(e) => e.preventDefault()}
/>| 规则 | 实现方式 |
|---|---|
| 自动填充 | 添加 |
| 输入类型 | 使用 |
| 输入模式 | 为纯数字字段添加 |
| 禁止阻止粘贴 | 不要使用 |
| 关闭拼写检查 | 对邮箱、验证码、用户名设置 |
| 未保存更改提示 | 导航前提示用户(使用 |
| 错误焦点 | 提交后聚焦第一个错误字段 |
| 共享点击区域 | 复选框/单选框的标签与控件合并为一个可点击区域 |
tsx
<input
type="email"
autoComplete="email"
spellCheck={false}
inputMode="email"
// 禁止:onPaste={(e) => e.preventDefault()}
/>Visual Design Checklist
视觉设计检查清单
| Check | Good | Bad |
|---|---|---|
| Hierarchy | Clear visual priority | Everything same size |
| Spacing | Consistent rhythm | Random gaps |
| Alignment | Elements aligned to grid | Misaligned elements |
| Interactive states | Hover/active/focus distinct | No state changes |
| Feedback | Clear response to actions | Silent interactions |
| 检查项 | 良好示例 | 不良示例 |
|---|---|---|
| 层级结构 | 清晰的视觉优先级 | 所有元素大小一致 |
| 间距 | 一致的节奏 | 随机间距 |
| 对齐 | 元素对齐到网格 | 元素错位 |
| 交互状态 | 悬停/激活/焦点状态区分明显 | 无状态变化 |
| 反馈机制 | 对操作有清晰响应 | 无反馈的交互 |
Visual Creativity (Avoid AI Slop)
视觉创意(避免AI通用风格)
When creating frontends, avoid generic AI aesthetics:
- Fonts: Choose distinctive typography, not defaults (avoid Inter, Roboto, Arial, system fonts)
- Colors: Commit to cohesive palette. Dominant colors with sharp accents > safe gradients
- Avoid: Purple gradients on white, predictable layouts, cookie-cutter Bootstrap/Tailwind defaults
- Icons: Use SVG icons (Heroicons, Lucide, Simple Icons). NEVER use emoji as UI icons
- Cursor: Add to ALL clickable elements
cursor-pointer - Hover: Use color/opacity transitions. Avoid transforms that shift layout
scale - Backgrounds: Add depth with subtle textures, gradients, or grain instead of flat colors
Make creative choices that feel designed for the specific context. No two designs should look the same.
创建前端界面时,避免使用通用AI美学:
- 字体:选择独特的排版,而非默认字体(避免Inter、Roboto、Arial、系统字体)
- 颜色:坚持使用统一的调色板。主色调搭配鲜明强调色 > 安全渐变
- 避免:白色背景上的紫色渐变、可预测的布局、千篇一律的Bootstrap/Tailwind默认样式
- 图标:使用SVG图标(Heroicons、Lucide、Simple Icons)。绝对不要使用emoji作为UI图标
- 光标:为所有可点击元素添加
cursor-pointer - 悬停效果:使用颜色/透明度过渡。避免使用会改变布局的变换
scale - 背景:使用微妙的纹理、渐变或颗粒感增加深度,而非纯色
根据设计思维阶段选定的美学方向做出创意选择。不同设计不应千篇一律。
Spatial Composition (Break the Grid)
空间构图(打破常规网格)
Move beyond safe, centered layouts:
| Technique | Effect | When to Use |
|---|---|---|
| Asymmetry | Dynamic tension, visual interest | Hero sections, feature highlights |
| Overlap | Depth, connection between elements | Cards, images, testimonials |
| Diagonal flow | Energy, movement | Landing pages, marketing |
| Grid-breaking | Emphasis, surprise | Key CTAs, focal points |
| Generous negative space | Luxury, breathing room | Premium products, editorial |
| Controlled density | Information-rich, productive | Dashboards, data-heavy UIs |
Rule: Match spatial composition to the aesthetic direction chosen in Design Thinking. Minimalist = negative space. Maximalist = controlled density.
超越安全的居中布局:
| 技巧 | 效果 | 适用场景 |
|---|---|---|
| 不对称布局 | 动态张力,视觉吸引力 | 首页横幅、功能亮点 |
| 元素重叠 | 层次感,元素间的关联性 | 卡片、图片、用户评价 |
| 对角线流 | 活力感,动感 | 着陆页、营销页面 |
| 打破网格 | 强调,惊喜感 | 关键CTA、焦点元素 |
| 充足的留白 | 奢华感,呼吸空间 | 高端产品、编辑类页面 |
| 受控的密度 | 信息丰富,高效 | 仪表盘、数据密集型UI |
规则: 空间构图需与设计思维阶段选定的美学方向匹配。极简主义=留白。极繁主义=受控密度。
Component Patterns
组件模式
Buttons
按钮
tsx
// Primary action button with all states
<button
type="button"
onClick={handleAction}
disabled={isLoading || isDisabled}
aria-busy={isLoading}
aria-disabled={isDisabled}
className={cn(
'btn-primary',
isLoading && 'btn-loading'
)}
>
{isLoading ? (
<>
<Spinner aria-hidden />
<span>Processing...</span>
</>
) : (
'Submit'
)}
</button>tsx
// 包含所有状态的主要操作按钮
<button
type="button"
onClick={handleAction}
disabled={isLoading || isDisabled}
aria-busy={isLoading}
aria-disabled={isDisabled}
className={cn(
'btn-primary',
isLoading && 'btn-loading'
)}
>
{isLoading ? (
<>
<Spinner aria-hidden />
<span>处理中...</span>
</>
) : (
'提交'
)}
</button>Forms with Validation
带验证的表单
tsx
<form onSubmit={handleSubmit} noValidate>
<div className="form-field">
<label htmlFor="email">
Email <span aria-hidden>*</span>
<span className="sr-only">(required)</span>
</label>
<input
id="email"
type="email"
value={email}
onChange={handleChange}
aria-invalid={errors.email ? 'true' : undefined}
aria-describedby={errors.email ? 'email-error' : 'email-hint'}
required
/>
<span id="email-hint" className="hint">
We'll never share your email
</span>
{errors.email && (
<span id="email-error" role="alert" className="error">
{errors.email}
</span>
)}
</div>
</form>tsx
<form onSubmit={handleSubmit} noValidate>
<div className="form-field">
<label htmlFor="email">
邮箱 <span aria-hidden>*</span>
<span className="sr-only">(必填)</span>
</label>
<input
id="email"
type="email"
value={email}
onChange={handleChange}
aria-invalid={errors.email ? 'true' : undefined}
aria-describedby={errors.email ? 'email-error' : 'email-hint'}
required
/>
<span id="email-hint" className="hint">
我们绝不会分享您的邮箱
</span>
{errors.email && (
<span id="email-error" role="alert" className="error">
{errors.email}
</span>
)}
</div>
</form>Loading States
加载状态
tsx
function DataList({ isLoading, data, error }) {
if (isLoading) {
return (
<div aria-live="polite" aria-busy="true">
<Spinner />
<span>Loading items...</span>
</div>
);
}
if (error) {
return (
<div role="alert" className="error-state">
<p>Failed to load items: {error.message}</p>
<button onClick={retry}>Try again</button>
</div>
);
}
if (!data?.length) {
return (
<div className="empty-state">
<p>No items found</p>
<button onClick={createNew}>Create your first item</button>
</div>
);
}
return <ul>{data.map(item => <Item key={item.id} {...item} />)}</ul>;
}tsx
function DataList({ isLoading, data, error }) {
if (isLoading) {
return (
<div aria-live="polite" aria-busy="true">
<Spinner />
<span>加载数据中...</span>
</div>
);
}
if (error) {
return (
<div role="alert" className="error-state">
<p>加载失败:{error.message}</p>
<button onClick={retry}>重试</button>
</div>
);
}
if (!data?.length) {
return (
<div className="empty-state">
<p>暂无数据</p>
<button onClick={createNew}>创建第一条数据</button>
</div>
);
}
return <ul>{data.map(item => <Item key={item.id} {...item} />)}</ul>;
}Error Messages
错误提示
tsx
// Inline error with recovery action
<div role="alert" className="error-banner">
<Icon name="error" aria-hidden />
<div>
<p className="error-title">Upload failed</p>
<p className="error-detail">File too large. Maximum size is 10MB.</p>
</div>
<button onClick={selectFile}>Choose different file</button>
</div>tsx
// 带恢复操作的内联错误
<div role="alert" className="error-banner">
<Icon name="error" aria-hidden />
<div>
<p className="error-title">上传失败</p>
<p className="error-detail">文件过大,最大支持10MB。</p>
</div>
<button onClick={selectFile}>选择其他文件</button>
</div>Responsive Design Checklist
响应式设计检查清单
| Breakpoint | Check |
|---|---|
| Mobile (< 640px) | Touch targets 44px+, no horizontal scroll |
| Tablet (640-1024px) | Layout adapts, navigation accessible |
| Desktop (> 1024px) | Content readable, not too wide |
| 断点 | 检查项 |
|---|---|
| 移动端(< 640px) | 触摸目标≥44px,无横向滚动 |
| 平板端(640-1024px) | 布局自适应,导航可访问 |
| 桌面端(> 1024px) | 内容可读,宽度不过宽 |
Performance Rules
性能规则
| Rule | Why | Implementation |
|---|---|---|
| Virtualize large lists | >50 items kills performance | Use |
| No layout reads in render | Causes forced reflow | Avoid |
| Lazy load images | Reduces initial load | |
| Prioritize critical images | Faster LCP | |
| Preconnect CDN | Faster asset loading | |
| Preload fonts | Prevents FOUT | |
| 规则 | 原因 | 实现方式 |
|---|---|---|
| 虚拟化长列表 | 超过50条数据会严重影响性能 | 使用 |
| 渲染中不读取布局 | 会导致强制重排 | 避免在渲染中使用 |
| 懒加载图片 | 减少初始加载时间 | 对首屏以下的图片使用 |
| 优先加载关键图片 | 更快的LCP | 使用 |
| 预连接CDN | 更快的资源加载 | |
| 预加载字体 | 避免FOUT(无样式文本闪烁) | |
URL & State Management
URL与状态管理
URL should reflect UI state. If it uses , consider URL sync.
useState| State Type | URL Strategy |
|---|---|
| Filters/search | |
| Active tab | |
| Pagination | |
| Expanded panels | |
| Sort order | |
Benefits: Shareable links, back button works, refresh preserves state.
tsx
// Use nuqs, next-usequerystate, or similar
const [tab, setTab] = useQueryState('tab', { defaultValue: 'overview' })URL应反映UI状态。 如果使用,考虑与URL同步。
useState| 状态类型 | URL策略 |
|---|---|
| 筛选/搜索 | |
| 激活标签页 | |
| 分页 | |
| 展开面板 | |
| 排序顺序 | |
优势: 可分享链接、返回按钮正常工作、刷新保留状态。
tsx
// 使用nuqs、next-usequerystate或类似库
const [tab, setTab] = useQueryState('tab', { defaultValue: 'overview' })Touch & Mobile
触摸与移动端
| Rule | Implementation |
|---|---|
| 44px touch targets | Minimum for buttons, links, controls |
| No double-tap delay | |
| Modal scroll lock | |
| Safe areas | |
| Tap highlight | Set |
| 规则 | 实现方式 |
|---|---|
| 44px触摸目标 | 按钮、链接、控件的最小尺寸 |
| 消除双击延迟 | 对交互元素使用 |
| 弹窗滚动锁定 | 在弹窗/抽屉中使用 |
| 安全区域 | 对刘海屏使用 |
| 点击高亮 | 明确设置 |
Red Flags - STOP and Reconsider
危险信号 - 立即停止并重新考虑
If you find yourself:
- Designing UI before mapping user flow
- Focusing on aesthetics before functionality
- Ignoring accessibility ("we'll add it later")
- Not handling error states
- Not providing loading feedback
- Using color alone to convey information
- Making decisions based on "it looks nice"
STOP. Go back to user flow.
如果你发现自己在做以下事情:
- 未梳理用户流程就开始设计UI
- 先关注美学再关注功能
- 忽略无障碍设计(“以后再加”)
- 未处理错误状态
- 未提供加载反馈
- 仅用颜色传递信息
- 基于“看起来不错”做决策
立即停止。回到用户流程梳理。
Rationalization Prevention
避免合理化借口
| Excuse | Reality |
|---|---|
| "Most users don't use keyboard" | Some users ONLY use keyboard. |
| "We'll add accessibility later" | Retrofitting is 10x harder. |
| "Error states are edge cases" | Errors happen. Handle them. |
| "Loading is fast, no need for state" | Network varies. Show state. |
| "It looks better without labels" | Unlabeled inputs are inaccessible. |
| "Users can figure it out" | If it's confusing, fix it. |
| 借口 | 现实 |
|---|---|
| “大多数用户不使用键盘” | 有些用户只能使用键盘。 |
| “我们以后再加无障碍设计” | 后期改造的难度是前期的10倍。 |
| “错误状态是边缘情况” | 错误总会发生。必须处理。 |
| “加载很快,不需要状态提示” | 网络状况多变。必须显示状态。 |
| “没有标签看起来更好” | 无标签输入框是无障碍违规的。 |
| “用户能自己弄明白” | 如果用户感到困惑,就需要修复。 |
Anti-patterns Blocklist (Flag These)
反模式黑名单(必须标记)
| Anti-pattern | Why It's Wrong | Fix |
|---|---|---|
| Blocks accessibility zoom | Remove it |
| Blocks accessibility zoom | Remove it |
| Performance + unexpected effects | List properties explicitly |
| Removes focus indicator | Add |
| Not keyboard accessible | Use |
Images without | Causes layout shift (CLS) | Add explicit dimensions |
| Form inputs without labels | Inaccessible | Add |
Icon buttons without | Unnamed to screen readers | Add |
| Emoji icons (🚀 ✨ 💫) | Unprofessional, inconsistent | Use SVG icons |
| Hardcoded date/number formats | Breaks internationalization | Use |
| Disorienting, mobile issues | Use sparingly, desktop only |
| 反模式 | 错误原因 | 修复方案 |
|---|---|---|
| 阻止无障碍缩放 | 移除该设置 |
| 阻止无障碍缩放 | 移除该设置 |
| 性能问题 + 意外效果 | 明确列出过渡属性 |
| 移除了焦点指示器 | 添加 |
| 不支持键盘访问 | 使用 |
图片无 | 导致布局偏移(CLS) | 添加明确的尺寸 |
| 表单输入框无标签 | 无障碍违规 | 添加 |
图标按钮无 | 屏幕阅读器无法识别 | 添加 |
| 使用emoji图标(🚀 ✨ 💫) | 不专业,不一致 | 使用SVG图标 |
| 硬编码日期/数字格式 | 破坏国际化 | 使用 |
滥用 | 造成困扰,移动端问题 | 谨慎使用,仅限桌面端 |
Light/Dark Mode
明暗模式
| Rule | Light Mode | Dark Mode |
|---|---|---|
| Glass/transparent | | |
| Text contrast | Minimum 4.5:1 (slate-900) | Minimum 4.5:1 (slate-100) |
| Borders | | |
| HTML attribute | — | |
| Meta tag | Match background | Match background |
html
<!-- Dark mode setup -->
<html style="color-scheme: dark">
<head><meta name="theme-color" content="#0f172a"></head>| 规则 | 浅色模式 | 深色模式 |
|---|---|---|
| 玻璃态/透明 | | |
| 文本对比度 | 最低4.5:1(slate-900) | 最低4.5:1(slate-100) |
| 边框 | | |
| HTML属性 | — | 在 |
| Meta标签 | 匹配背景色 | 匹配背景色 |
html
<!-- 深色模式设置 -->
<html style="color-scheme: dark">
<head><meta name="theme-color" content="#0f172a"></head>Output Format
输出格式
markdown
undefinedmarkdown
undefinedFrontend Review: [Component/Feature]
前端评审:[组件/功能]
User Flow
用户流程
[Step-by-step what user is trying to do]
[用户试图完成的步骤]
Success Criteria
成功标准
- User can complete [task]
- User can recover from errors
- All users can access (keyboard, screen reader)
- Interface feels responsive
- 用户可完成[任务]
- 用户可从错误中恢复
- 所有用户可访问(键盘、屏幕阅读器)
- 界面响应迅速
UX Issues
UX问题
| Severity | Issue | Location | Impact | Fix |
|---|---|---|---|---|
| BLOCKS | [Issue] | | [Impact] | [Fix] |
| 严重等级 | 问题 | 位置 | 影响 | 修复方案 |
|---|---|---|---|---|
| 阻塞 | [问题] | | [影响] | [修复方案] |
Accessibility Issues
无障碍问题
| WCAG | Issue | Location | Fix |
|---|---|---|---|
| 1.4.3 | [Issue] | | [Fix] |
| WCAG标准 | 问题 | 位置 | 修复方案 |
|---|---|---|---|
| 1.4.3 | [问题] | | [修复方案] |
Visual Issues
视觉问题
| Issue | Location | Fix |
|---|---|---|
| [Issue] | | [Fix] |
| 问题 | 位置 | 修复方案 |
|---|---|---|
| [问题] | | [修复方案] |
Recommendations
建议
- [Most critical fix]
- [Second fix]
undefined- [最关键的修复]
- [次要修复]
undefinedUI States Checklist (CRITICAL)
UI状态检查清单(至关重要)
Before completing ANY UI component:
完成任何UI组件前必须检查:
States
状态
- Error state handled and shown to user
- Loading state shown ONLY when no data exists
- Empty state provided for all collections/lists
- Success state with appropriate feedback
- 错误状态已处理并展示给用户
- 加载状态仅在无数据时显示
- 所有集合/列表都有空状态
- 提供适当的成功状态反馈
Buttons & Mutations
按钮与变更操作
- Buttons disabled during async operations
- Buttons show loading indicator
- Mutations have onError handler with user feedback
- No double-click possible on submit buttons
- 异步操作期间按钮禁用
- 按钮显示加载指示器
- 变更操作有onError处理并提供用户反馈
- 提交按钮无法被双击
Data Handling
数据处理
- State order: Error → Loading (no data) → Empty → Success
- All user actions have feedback (toast/visual)
- 状态顺序:错误 → 加载(无数据) → 空 → 成功
- 所有用户操作都有反馈(toast/视觉提示)
Final Check
最终检查
Before completing frontend work:
- User flow mapped and understood
- All states handled (loading, error, empty, success)
- Keyboard navigation works
- Screen reader tested
- Color contrast verified (4.5:1 minimum)
- Touch targets adequate on mobile (44px+)
- Error messages clear and actionable
- Success criteria met
- No emoji icons (SVG only)
- respected
prefers-reduced-motion - Light/dark mode contrast verified
- on all clickable elements
cursor-pointer - No in codebase
transition: all
完成前端工作前:
- 用户流程已梳理并理解
- 所有状态已处理(加载、错误、空、成功)
- 键盘导航正常工作
- 已测试屏幕阅读器
- 已验证颜色对比度(最低4.5:1)
- 移动端触摸目标足够(≥44px)
- 错误提示清晰且可操作
- 满足成功标准
- 无emoji图标(仅使用SVG)
- 已尊重设置
prefers-reduced-motion - 已验证明暗模式的对比度
- 所有可点击元素都有
cursor-pointer - 代码库中无",
transition: all