web-design-guidelines

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Web 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

按优先级划分的规则类别

PriorityCategoryImpactPrefix
1Accessibility - Semantic StructureCRITICAL
a11y-
2Accessibility - Keyboard & FocusCRITICAL
a11y-
3Accessibility - Visual & ColorCRITICAL
a11y-
4Forms - Input & ValidationCRITICAL
form-
5Forms - Error HandlingHIGH
form-
6Forms - User ExperienceMEDIUM
form-
7Animation & MotionCRITICAL
motion-
8Performance & UXMEDIUM
perf-
优先级类别影响程度前缀
1无障碍设计 - 语义化结构CRITICAL
a11y-
2无障碍设计 - 键盘与焦点CRITICAL
a11y-
3无障碍设计 - 视觉与色彩CRITICAL
a11y-
4表单 - 输入与验证CRITICAL
form-
5表单 - 错误处理HIGH
form-
6表单 - 用户体验MEDIUM
form-
7动画与动效CRITICAL
motion-
8性能与用户体验MEDIUM
perf-

Quick Reference

快速参考

1. Accessibility - Semantic Structure (CRITICAL)

1. 无障碍设计 - 语义化结构(CRITICAL)

  • a11y-semantic-html
    - Use semantic HTML elements
  • a11y-heading-hierarchy
    - Maintain proper heading hierarchy
  • a11y-screen-reader
    - Optimize for screen reader compatibility
  • a11y-skip-links
    - Provide skip links for navigation
  • a11y-semantic-html
    - 使用语义化HTML元素
  • a11y-heading-hierarchy
    - 保持合理的标题层级
  • a11y-screen-reader
    - 优化屏幕阅读器兼容性
  • a11y-skip-links
    - 提供导航跳转链接

2. Accessibility - Keyboard & Focus (CRITICAL)

2. 无障碍设计 - 键盘与焦点(CRITICAL)

  • a11y-keyboard-nav
    - Ensure full keyboard navigation
  • a11y-focus-management
    - Manage keyboard focus properly
  • a11y-aria-labels
    - Add ARIA labels to interactive elements
  • a11y-keyboard-nav
    - 确保完整的键盘导航支持
  • a11y-focus-management
    - 正确管理键盘焦点
  • a11y-aria-labels
    - 为交互元素添加ARIA标签

3. Accessibility - Visual & Color (CRITICAL)

3. 无障碍设计 - 视觉与色彩(CRITICAL)

  • a11y-color-contrast
    - Ensure sufficient color contrast
  • a11y-alt-text
    - Provide meaningful alt text for images
  • a11y-color-contrast
    - 确保足够的色彩对比度
  • a11y-alt-text
    - 为图片添加有意义的替代文本

4. Forms - Input & Validation (CRITICAL)

4. 表单 - 输入与验证(CRITICAL)

  • form-autocomplete
    - Use autocomplete attributes for forms
  • form-input-types
    - Use correct input types
  • form-labels
    - Associate labels with form inputs
  • form-autocomplete
    - 为表单使用自动完成属性
  • form-input-types
    - 使用正确的输入类型
  • form-labels
    - 为表单输入项关联标签

5. Forms - Error Handling (HIGH)

5. 表单 - 错误处理(HIGH)

  • form-error-display
    - Display form errors clearly
  • form-error-messages
    - Provide accessible error messages
  • form-validation-ux
    - Design user-friendly form validation
  • form-error-display
    - 清晰显示表单错误
  • form-error-messages
    - 提供无障碍的错误提示信息
  • form-validation-ux
    - 设计用户友好的表单验证逻辑

6. Forms - User Experience (MEDIUM)

6. 表单 - 用户体验(MEDIUM)

  • form-inline-validation
    - Implement smart inline validation
  • form-multi-step
    - Design effective multi-step forms
  • form-placeholder-usage
    - Use placeholders appropriately
  • form-submit-feedback
    - Provide clear form submission feedback
  • form-inline-validation
    - 实现智能即时验证
  • form-multi-step
    - 设计高效的多步骤表单
  • form-placeholder-usage
    - 合理使用占位符
  • form-submit-feedback
    - 提供清晰的表单提交反馈

7. Animation & Motion (CRITICAL)

7. 动画与动效(CRITICAL)

  • motion-reduced
    - Respect prefers-reduced-motion preference
  • 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 issue
Example:
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.md
Each 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