web-design-guidelines
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseWeb Design Guidelines
Web设计指南
Comprehensive UI/UX and accessibility guidelines for building inclusive, performant web interfaces. Contains 21 rules across 8 categories, prioritized by WCAG compliance and user impact.
这份指南是构建包容性、高性能Web界面的全面UI/UX与无障碍设计准则,包含8个类别共21条规则,依据WCAG合规性和用户影响程度划分优先级。
When to Apply
适用场景
Reference these guidelines when:
- Reviewing UI code for accessibility
- Implementing forms and interactions
- Optimizing performance
- Ensuring cross-browser compatibility
- Improving user experience
在以下场景中可参考本指南:
- 审查UI代码的无障碍性
- 实现表单与交互功能
- 优化性能
- 确保跨浏览器兼容性
- 提升用户体验
Rule Categories by Priority
按优先级划分的规则类别
| Priority | Category | Impact | Prefix |
|---|---|---|---|
| 1 | Accessibility - Semantic Structure | CRITICAL | |
| 2 | Accessibility - Keyboard & Focus | CRITICAL | |
| 3 | Accessibility - Visual & Color | CRITICAL | |
| 4 | Forms - Input & Validation | CRITICAL | |
| 5 | Forms - Error Handling | HIGH | |
| 6 | Forms - User Experience | MEDIUM | |
| 7 | Animation & Motion | CRITICAL | |
| 8 | Performance & UX | MEDIUM | |
| 优先级 | 类别 | 影响程度 | 前缀 |
|---|---|---|---|
| 1 | 无障碍设计 - 语义化结构 | CRITICAL | |
| 2 | 无障碍设计 - 键盘与焦点 | CRITICAL | |
| 3 | 无障碍设计 - 视觉与色彩 | CRITICAL | |
| 4 | 表单 - 输入与验证 | CRITICAL | |
| 5 | 表单 - 错误处理 | HIGH | |
| 6 | 表单 - 用户体验 | MEDIUM | |
| 7 | 动画与动效 | CRITICAL | |
| 8 | 性能与用户体验 | MEDIUM | |
Quick Reference
快速参考
1. Accessibility - Semantic Structure (CRITICAL)
1. 无障碍设计 - 语义化结构(CRITICAL)
- - Use semantic HTML elements
a11y-semantic-html - - Maintain proper heading hierarchy
a11y-heading-hierarchy - - Optimize for screen reader compatibility
a11y-screen-reader - - Provide skip links for navigation
a11y-skip-links
- - 使用语义化HTML元素
a11y-semantic-html - - 保持合理的标题层级
a11y-heading-hierarchy - - 优化屏幕阅读器兼容性
a11y-screen-reader - - 提供导航跳转链接
a11y-skip-links
2. Accessibility - Keyboard & Focus (CRITICAL)
2. 无障碍设计 - 键盘与焦点(CRITICAL)
- - Ensure full keyboard navigation
a11y-keyboard-nav - - Manage keyboard focus properly
a11y-focus-management - - Add ARIA labels to interactive elements
a11y-aria-labels
- - 确保完整的键盘导航支持
a11y-keyboard-nav - - 正确管理键盘焦点
a11y-focus-management - - 为交互元素添加ARIA标签
a11y-aria-labels
3. Accessibility - Visual & Color (CRITICAL)
3. 无障碍设计 - 视觉与色彩(CRITICAL)
- - Ensure sufficient color contrast
a11y-color-contrast - - Provide meaningful alt text for images
a11y-alt-text
- - 确保足够的色彩对比度
a11y-color-contrast - - 为图片添加有意义的替代文本
a11y-alt-text
4. Forms - Input & Validation (CRITICAL)
4. 表单 - 输入与验证(CRITICAL)
- - Use autocomplete attributes for forms
form-autocomplete - - Use correct input types
form-input-types - - Associate labels with form inputs
form-labels
- - 为表单使用自动完成属性
form-autocomplete - - 使用正确的输入类型
form-input-types - - 为表单输入项关联标签
form-labels
5. Forms - Error Handling (HIGH)
5. 表单 - 错误处理(HIGH)
- - Display form errors clearly
form-error-display - - Provide accessible error messages
form-error-messages - - Design user-friendly form validation
form-validation-ux
- - 清晰显示表单错误
form-error-display - - 提供无障碍的错误提示信息
form-error-messages - - 设计用户友好的表单验证逻辑
form-validation-ux
6. Forms - User Experience (MEDIUM)
6. 表单 - 用户体验(MEDIUM)
- - Implement smart inline validation
form-inline-validation - - Design effective multi-step forms
form-multi-step - - Use placeholders appropriately
form-placeholder-usage - - Provide clear form submission feedback
form-submit-feedback
- - 实现智能即时验证
form-inline-validation - - 设计高效的多步骤表单
form-multi-step - - 合理使用占位符
form-placeholder-usage - - 提供清晰的表单提交反馈
form-submit-feedback
7. Animation & Motion (CRITICAL)
7. 动画与动效(CRITICAL)
- - Respect prefers-reduced-motion preference
motion-reduced
- - 尊重用户的“减少动效”偏好设置
motion-reduced
8. Performance & UX (MEDIUM)
8. 性能与用户体验(MEDIUM)
- Image optimization and layout stability patterns
- 图片优化与布局稳定性方案
Essential Guidelines
核心准则
Semantic HTML
语义化HTML
tsx
// ❌ Div soup - no semantic meaning
<div className="header">
<div className="nav">
<div onClick={handleClick}>Home</div>
</div>
</div>
<div className="content">
<div className="title">Page Title</div>
<div className="text">Content here...</div>
</div>
// ✅ Semantic HTML - accessible and meaningful
<header>
<nav aria-label="Main navigation">
<a href="/">Home</a>
</nav>
</header>
<main>
<article>
<h1>Page Title</h1>
<p>Content here...</p>
</article>
</main>tsx
// ❌ 无意义的Div嵌套
<div className="header">
<div className="nav">
<div onClick={handleClick}>Home</div>
</div>
</div>
<div className="content">
<div className="title">Page Title</div>
<div className="text">Content here...</div>
</div>
// ✅ 语义化HTML - 无障碍且具备语义
<header>
<nav aria-label="Main navigation">
<a href="/">Home</a>
</nav>
</header>
<main>
<article>
<h1>Page Title</h1>
<p>Content here...</p>
</article>
</main>ARIA Labels
ARIA标签
tsx
// Interactive elements need accessible names
<button aria-label="Close dialog">
<XIcon />
</button>
<button aria-label="Add to cart">
<PlusIcon />
</button>
// Icon-only links
<a href="/settings" aria-label="Settings">
<SettingsIcon />
</a>
// Decorative icons should be hidden
<span aria-hidden="true">🎉</span>tsx
// 交互元素需要无障碍名称
<button aria-label="Close dialog">
<XIcon />
</button>
<button aria-label="Add to cart">
<PlusIcon />
</button>
// 纯图标链接
<a href="/settings" aria-label="Settings">
<SettingsIcon />
</a>
// 装饰性图标应隐藏
<span aria-hidden="true">🎉</span>Keyboard Navigation
键盘导航
tsx
// All interactive elements must be keyboard accessible
function Dialog({ isOpen, onClose, children }) {
// Trap focus inside dialog
const dialogRef = useRef<HTMLDivElement>(null)
useEffect(() => {
if (isOpen) {
dialogRef.current?.focus()
}
}, [isOpen])
// Handle Escape key
const handleKeyDown = (e: React.KeyboardEvent) => {
if (e.key === 'Escape') {
onClose()
}
}
return (
<div
ref={dialogRef}
role="dialog"
aria-modal="true"
tabIndex={-1}
onKeyDown={handleKeyDown}
>
{children}
<button onClick={onClose}>Close</button>
</div>
)
}tsx
// 所有交互元素必须支持键盘访问
function Dialog({ isOpen, onClose, children }) {
// 将焦点锁定在弹窗内
const dialogRef = useRef<HTMLDivElement>(null)
useEffect(() => {
if (isOpen) {
dialogRef.current?.focus()
}
}, [isOpen])
// 处理Esc按键
const handleKeyDown = (e: React.KeyboardEvent) => {
if (e.key === 'Escape') {
onClose()
}
}
return (
<div
ref={dialogRef}
role="dialog"
aria-modal="true"
tabIndex={-1}
onKeyDown={handleKeyDown}
>
{children}
<button onClick={onClose}>Close</button>
</div>
)
}Focus Styles
焦点样式
tsx
// ✅ Always visible focus styles
<button className="
focus:outline-none
focus-visible:ring-2
focus-visible:ring-blue-500
focus-visible:ring-offset-2
">
Button
</button>
// ❌ Never remove focus outlines without replacement
<button className="outline-none focus:outline-none">
Inaccessible
</button>tsx
// ✅ 始终保持可见的焦点样式
<button className="
focus:outline-none
focus-visible:ring-2
focus-visible:ring-blue-500
focus-visible:ring-offset-2
">
Button
</button>
// ❌ 绝不能在未替代的情况下移除焦点轮廓
<button className="outline-none focus:outline-none">
Inaccessible
</button>Form Accessibility
表单无障碍设计
tsx
// ✅ Properly labeled form
<form>
<div>
<label htmlFor="email">
Email address
<span aria-hidden="true" className="text-red-500">*</span>
</label>
<input
id="email"
type="email"
name="email"
required
aria-required="true"
aria-describedby="email-hint email-error"
autoComplete="email"
/>
<p id="email-hint" className="text-gray-500 text-sm">
We'll never share your email.
</p>
{error && (
<p id="email-error" role="alert" className="text-red-500 text-sm">
{error}
</p>
)}
</div>
<button type="submit">Subscribe</button>
</form>tsx
// ✅ 正确标记的表单
<form>
<div>
<label htmlFor="email">
Email address
<span aria-hidden="true" className="text-red-500">*</span>
</label>
<input
id="email"
type="email"
name="email"
required
aria-required="true"
aria-describedby="email-hint email-error"
autoComplete="email"
/>
<p id="email-hint" className="text-gray-500 text-sm">
We'll never share your email.
</p>
{error && (
<p id="email-error" role="alert" className="text-red-500 text-sm">
{error}
</p>
)}
</div>
<button type="submit">Subscribe</button>
</form>Respect Reduced Motion
尊重减少动效偏好
tsx
// CSS
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
// Tailwind
<div className="
transition-transform duration-300
hover:scale-105
motion-reduce:transition-none
motion-reduce:hover:transform-none
">
Card
</div>
// JavaScript
const prefersReducedMotion = window.matchMedia(
'(prefers-reduced-motion: reduce)'
).matches
function animate() {
if (prefersReducedMotion) {
// Skip or simplify animation
return
}
// Full animation
}tsx
// CSS
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
// Tailwind
<div className="
transition-transform duration-300
hover:scale-105
motion-reduce:transition-none
motion-reduce:hover:transform-none
">
Card
</div>
// JavaScript
const prefersReducedMotion = window.matchMedia(
'(prefers-reduced-motion: reduce)'
).matches
function animate() {
if (prefersReducedMotion) {
// 跳过或简化动画
return
}
// 完整动画逻辑
}Image Handling
图片处理
tsx
// ✅ Proper image implementation
<img
src="/hero.webp"
alt="Team collaborating around a whiteboard"
width={1200}
height={600}
loading="lazy"
decoding="async"
/>
// ✅ Decorative images
<img src="/pattern.svg" alt="" aria-hidden="true" />
// ✅ Responsive images
<picture>
<source
srcSet="/hero-mobile.webp"
media="(max-width: 768px)"
type="image/webp"
/>
<source srcSet="/hero.webp" type="image/webp" />
<img src="/hero.jpg" alt="Hero description" width={1200} height={600} />
</picture>tsx
// ✅ 规范的图片实现
<img
src="/hero.webp"
alt="Team collaborating around a whiteboard"
width={1200}
height={600}
loading="lazy"
decoding="async"
/>
// ✅ 装饰性图片
<img src="/pattern.svg" alt="" aria-hidden="true" />
// ✅ 响应式图片
<picture>
<source
srcSet="/hero-mobile.webp"
media="(max-width: 768px)"
type="image/webp"
/>
<source srcSet="/hero.webp" type="image/webp" />
<img src="/hero.jpg" alt="Hero description" width={1200} height={600} />
</picture>Touch Targets
触摸目标
tsx
// ✅ Minimum 44x44px touch targets
<button className="min-h-[44px] min-w-[44px] p-2">
<Icon className="w-6 h-6" />
</button>
// ✅ Adequate spacing between touch targets
<nav className="flex gap-2">
<a href="/" className="p-3">Home</a>
<a href="/about" className="p-3">About</a>
</nav>tsx
// ✅ 最小44x44px的触摸目标
<button className="min-h-[44px] min-w-[44px] p-2">
<Icon className="w-6 h-6" />
</button>
// ✅ 触摸目标间保持足够间距
<nav className="flex gap-2">
<a href="/" className="p-3">Home</a>
<a href="/about" className="p-3">About</a>
</nav>Color Contrast
色彩对比度
css
/* WCAG AA requires 4.5:1 for normal text, 3:1 for large text */
/* ❌ Insufficient contrast */
.low-contrast {
color: #999999; /* Gray on white: ~2.8:1 */
background: white;
}
/* ✅ Sufficient contrast */
.good-contrast {
color: #595959; /* Darker gray: ~7:1 */
background: white;
}
/* ✅ Don't rely on color alone */
.error {
color: #dc2626;
border-left: 4px solid #dc2626; /* Visual indicator */
}css
/* WCAG AA标准要求普通文本对比度达到4.5:1,大文本达到3:1 */
/* ❌ 对比度不足 */
.low-contrast {
color: #999999; /* 灰色在白色背景上:约2.8:1 */
background: white;
}
/* ✅ 足够的对比度 */
.good-contrast {
color: #595959; /* 深灰色:约7:1 */
background: white;
}
/* ✅ 不能仅依赖色彩传递信息 */
.error {
color: #dc2626;
border-left: 4px solid #dc2626; /* 视觉指示器 */
}Live Regions
实时区域
tsx
// Announce dynamic content to screen readers
<div
role="status"
aria-live="polite"
aria-atomic="true"
className="sr-only"
>
{message}
</div>
// Toast notifications
function Toast({ message }: { message: string }) {
return (
<div
role="alert"
aria-live="assertive"
className="fixed bottom-4 right-4 bg-gray-900 text-white p-4 rounded"
>
{message}
</div>
)
}tsx
// 向屏幕阅读器播报动态内容
<div
role="status"
aria-live="polite"
aria-atomic="true"
className="sr-only"
>
{message}
</div>
// 提示通知
function Toast({ message }: { message: string }) {
return (
<div
role="alert"
aria-live="assertive"
className="fixed bottom-4 right-4 bg-gray-900 text-white p-4 rounded"
>
{message}
</div>
)
}Output Format
输出格式
When auditing code, output findings in this format:
file:line - [category] Description of issueExample:
src/components/Button.tsx:15 - [a11y] Missing aria-label on icon-only button
src/pages/Home.tsx:42 - [perf] Image missing width/height attributes
src/components/Form.tsx:28 - [form] Input missing associated label审核代码时,按以下格式输出结果:
file:line - [category] 问题描述示例:
src/components/Button.tsx:15 - [a11y] 纯图标按钮缺少aria-label
src/pages/Home.tsx:42 - [perf] 图片缺少width/height属性
src/components/Form.tsx:28 - [form] 输入项未关联标签How to Use
使用方法
Read individual rule files for detailed explanations and code examples:
rules/a11y-semantic-html.md
rules/form-autocomplete.md
rules/motion-reduced.md
rules/_sections.mdEach rule file contains:
- YAML frontmatter with metadata (title, impact, tags)
- Brief explanation of why it matters
- Incorrect code example with explanation
- Correct code example with explanation
- Additional context and WCAG references
阅读单个规则文件获取详细说明和代码示例:
rules/a11y-semantic-html.md
rules/form-autocomplete.md
rules/motion-reduced.md
rules/_sections.md每个规则文件包含:
- 带元数据的YAML前置内容(标题、影响程度、标签)
- 规则重要性的简要说明
- 错误代码示例及解释
- 正确代码示例及解释
- 额外说明与WCAG参考链接
Full Compiled Document
完整编译文档
For the complete guide with all rules expanded:
AGENTS.md如需查看包含所有规则详情的完整指南,请查阅:
AGENTS.md