返回博客列表
设计开发

设计系统构建指南

2025-09-05
15 分钟阅读
设计系统UI/UX组件库
设计系统构建指南

设计系统构建指南

设计系统是现代产品开发中不可或缺的一部分。它不仅能提高开发效率,还能确保产品的一致性和可维护性。

什么是设计系统?

设计系统是一套完整的设计标准,包括:

  • 设计原则:指导设计决策的核心价值观
  • 视觉语言:颜色、字体、图标、间距等视觉元素
  • 组件库:可复用的 UI 组件
  • 设计规范:使用指南和最佳实践
  • 工具链:支持设计和开发的工具

设计原则

1. 一致性 (Consistency)

保持整个产品的一致性,包括视觉风格、交互模式和用户体验。

2. 可访问性 (Accessibility)

确保所有用户都能使用产品,包括残障用户。

3. 可扩展性 (Scalability)

设计系统应该能够适应不同规模和复杂度的项目。

4. 效率 (Efficiency)

通过复用组件和规范,提高设计和开发效率。

视觉语言设计

颜色系统

:root {
  /* 主色调 */
  --primary-50: #eff6ff;
  --primary-100: #dbeafe;
  --primary-500: #3b82f6;
  --primary-600: #2563eb;
  --primary-900: #1e3a8a;
  
  /* 中性色 */
  --gray-50: #f9fafb;
  --gray-100: #f3f4f6;
  --gray-500: #6b7280;
  --gray-900: #111827;
  
  /* 语义色 */
  --success: #10b981;
  --warning: #f59e0b;
  --error: #ef4444;
  --info: #3b82f6;
}

字体系统

:root {
  /* 字体族 */
  --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
  --font-mono: 'Fira Code', 'Monaco', 'Consolas', monospace;
  
  /* 字体大小 */
  --text-xs: 0.75rem;    /* 12px */
  --text-sm: 0.875rem;   /* 14px */
  --text-base: 1rem;     /* 16px */
  --text-lg: 1.125rem;   /* 18px */
  --text-xl: 1.25rem;    /* 20px */
  --text-2xl: 1.5rem;    /* 24px */
  
  /* 行高 */
  --leading-tight: 1.25;
  --leading-normal: 1.5;
  --leading-relaxed: 1.75;
}

间距系统

:root {
  --space-1: 0.25rem;   /* 4px */
  --space-2: 0.5rem;    /* 8px */
  --space-3: 0.75rem;   /* 12px */
  --space-4: 1rem;      /* 16px */
  --space-6: 1.5rem;    /* 24px */
  --space-8: 2rem;      /* 32px */
  --space-12: 3rem;     /* 48px */
  --space-16: 4rem;     /* 64px */
}

组件库构建

1. 基础组件

// Button 组件
interface ButtonProps {
  variant?: 'primary' | 'secondary' | 'outline'
  size?: 'sm' | 'md' | 'lg'
  disabled?: boolean
  children: React.ReactNode
  onClick?: () => void
}

export function Button({ 
  variant = 'primary', 
  size = 'md', 
  disabled = false,
  children,
  onClick 
}: ButtonProps) {
  const baseClasses = 'inline-flex items-center justify-center rounded-md font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2'
  
  const variantClasses = {
    primary: 'bg-primary text-primary-foreground hover:bg-primary/90',
    secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
    outline: 'border border-input bg-background hover:bg-accent'
  }
  
  const sizeClasses = {
    sm: 'h-9 px-3 text-sm',
    md: 'h-10 px-4 py-2',
    lg: 'h-11 px-8 text-lg'
  }
  
  return (
    <button
      className={cn(
        baseClasses,
        variantClasses[variant],
        sizeClasses[size],
        disabled && 'opacity-50 cursor-not-allowed'
      )}
      disabled={disabled}
      onClick={onClick}
    >
      {children}
    </button>
  )
}

2. 复合组件

// Card 组件
interface CardProps {
  children: React.ReactNode
  className?: string
}

export function Card({ children, className }: CardProps) {
  return (
    <div className={cn('rounded-lg border bg-card text-card-foreground shadow-sm', className)}>
      {children}
    </div>
  )
}

interface CardHeaderProps {
  children: React.ReactNode
  className?: string
}

export function CardHeader({ children, className }: CardHeaderProps) {
  return (
    <div className={cn('flex flex-col space-y-1.5 p-6', className)}>
      {children}
    </div>
  )
}

interface CardContentProps {
  children: React.ReactNode
  className?: string
}

export function CardContent({ children, className }: CardContentProps) {
  return (
    <div className={cn('p-6 pt-0', className)}>
      {children}
    </div>
  )
}

3. 表单组件

// Input 组件
interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
  label?: string
  error?: string
  helperText?: string
}

export function Input({ label, error, helperText, className, ...props }: InputProps) {
  return (
    <div className="space-y-2">
      {label && (
        <label className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70">
          {label}
        </label>
      )}
      <input
        className={cn(
          'flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
          error && 'border-destructive focus-visible:ring-destructive',
          className
        )}
        {...props}
      />
      {error && (
        <p className="text-sm text-destructive">{error}</p>
      )}
      {helperText && !error && (
        <p className="text-sm text-muted-foreground">{helperText}</p>
      )}
    </div>
  )
}

设计规范文档

1. 组件使用指南

# Button 组件使用指南

## 基本用法

```tsx
<Button>点击我</Button>
<Button variant="secondary">次要按钮</Button>
<Button variant="outline">轮廓按钮</Button>

尺寸

<Button size="sm">小按钮</Button>
<Button size="md">中等按钮</Button>
<Button size="lg">大按钮</Button>

状态

<Button disabled>禁用按钮</Button>

最佳实践

  • 主要操作使用 primary 变体
  • 次要操作使用 secondary 或 outline 变体
  • 危险操作使用 error 变体
  • 按钮文字应该简洁明了

### 2. 设计原则文档

```markdown
# 设计原则

## 一致性

- 使用统一的颜色、字体和间距
- 保持相同的交互模式
- 遵循既定的视觉层次

## 可访问性

- 确保足够的颜色对比度
- 提供键盘导航支持
- 使用语义化的 HTML 标签

## 响应式设计

- 移动优先的设计方法
- 灵活的布局系统
- 适配不同屏幕尺寸

工具链建设

1. Storybook 集成

// .storybook/main.js
module.exports = {
  stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'],
  addons: [
    '@storybook/addon-essentials',
    '@storybook/addon-a11y',
    '@storybook/addon-docs'
  ],
  framework: '@storybook/react',
  typescript: {
    check: false,
    reactDocgen: 'react-docgen-typescript'
  }
}

2. 自动化测试

// Button.test.tsx
import { render, screen, fireEvent } from '@testing-library/react'
import { Button } from './Button'

describe('Button', () => {
  it('renders correctly', () => {
    render(<Button>Click me</Button>)
    expect(screen.getByRole('button')).toBeInTheDocument()
  })
  
  it('handles click events', () => {
    const handleClick = jest.fn()
    render(<Button onClick={handleClick}>Click me</Button>)
    
    fireEvent.click(screen.getByRole('button'))
    expect(handleClick).toHaveBeenCalledTimes(1)
  })
  
  it('is disabled when disabled prop is true', () => {
    render(<Button disabled>Click me</Button>)
    expect(screen.getByRole('button')).toBeDisabled()
  })
})

3. 设计令牌管理

// design-tokens.js
export const tokens = {
  colors: {
    primary: {
      50: '#eff6ff',
      100: '#dbeafe',
      500: '#3b82f6',
      600: '#2563eb',
      900: '#1e3a8a'
    }
  },
  spacing: {
    xs: '0.25rem',
    sm: '0.5rem',
    md: '1rem',
    lg: '1.5rem',
    xl: '2rem'
  },
  typography: {
    fontFamily: {
      sans: ['Inter', 'sans-serif'],
      mono: ['Fira Code', 'monospace']
    },
    fontSize: {
      xs: '0.75rem',
      sm: '0.875rem',
      base: '1rem',
      lg: '1.125rem',
      xl: '1.25rem'
    }
  }
}

实施策略

1. 渐进式实施

  • 从核心组件开始
  • 逐步扩展到复杂组件
  • 持续迭代和改进

2. 团队协作

  • 设计师和开发者密切合作
  • 建立清晰的沟通机制
  • 定期审查和更新

3. 版本管理

{
  "name": "@company/design-system",
  "version": "1.2.0",
  "description": "Company Design System",
  "main": "dist/index.js",
  "types": "dist/index.d.ts",
  "files": [
    "dist"
  ],
  "scripts": {
    "build": "tsc",
    "test": "jest",
    "storybook": "storybook dev -p 6006",
    "build-storybook": "storybook build"
  }
}

最佳实践

1. 组件设计

  • 单一职责原则
  • 可组合性
  • 可配置性
  • 可访问性

2. 文档维护

  • 及时更新文档
  • 提供使用示例
  • 记录变更历史

3. 质量保证

  • 自动化测试
  • 代码审查
  • 性能监控

总结

设计系统是一个持续演进的过程,需要团队协作、工具支持和最佳实践。通过建立完善的设计系统,我们可以:

  • 提高开发效率
  • 确保产品一致性
  • 降低维护成本
  • 改善用户体验

记住,设计系统不是一成不变的,需要根据项目需求和用户反馈不断优化和改进。