设计系统建立完整指南:从零到一构建企业级设计基础设施
设计系统是现代产品开发的基础设施。它不仅是一套组件库,更是一种工作方式、一套标准、一个生态系统。本文将详细讲解如何从零开始构建一套完整的企业级设计系统。
什么是设计系统
设计系统的定义
设计系统是一套完整的标准集合,包含设计原则、视觉语言、组件库、模式库和最佳实践,用于指导产品的设计和开发。
┌─────────────────────────────────────────────────────────────┐
│ 设计系统金字塔 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌───────────────┐ │
│ │ 产品体验 │ ← 最终用户感知 │
│ └───────────────┘ │
│ ┌───────────────────┐ │
│ │ 页面模板 │ ← 页面级布局模式 │
│ └───────────────────┘ │
│ ┌───────────────────────┐ │
│ │ 组件 & 模式 │ ← 可复用 UI 单元 │
│ └───────────────────────┘ │
│ ┌───────────────────────────┐ │
│ │ 设计令牌 │ ← 原子级变量 │
│ └───────────────────────────┘ │
│ ┌───────────────────────────────┐ │
│ │ 设计原则 │ ← 指导思想 │
│ └───────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
设计系统 vs 组件库 vs 风格指南
| 概念 | 内容 | 用途 |
|---|---|---|
| 风格指南 | 颜色、字体、间距等视觉规范 | 保持视觉一致性 |
| 组件库 | 可复用的 UI 组件代码 | 提高开发效率 |
| 设计系统 | 原则 + 规范 + 组件 + 模式 + 文档 + 工具 | 全方位产品设计基础设施 |
建立设计系统的价值
对设计团队:
- 减少重复设计工作 80%+
- 统一设计语言,新成员快速上手
- 更多时间聚焦创新和用户体验
对开发团队:
- 组件复用率提升,开发效率翻倍
- 减少设计沟通成本
- 代码更加规范和可维护
对产品团队:
- 产品体验一致性保障
- 快速迭代,缩短上市时间
- 降低设计和开发债务
对企业:
- 品牌形象统一
- 跨团队协作效率提升
- 长期成本节约
设计原则制定
设计原则是设计系统的灵魂,指导所有设计决策。
制定原则的方法
1. 从品牌价值观出发
品牌价值观 → 设计原则
───────────────────────────────────────────
可靠、专业 → 简洁、克制
创新、年轻 → 大胆、活力
亲和、温暖 → 圆润、柔和
高效、智能 → 直接、智能
2. 从用户需求出发
用户需求 → 设计原则
───────────────────────────────────────────
快速完成任务 → 效率优先
减少学习成本 → 直观易懂
信任和安全感 → 可预测、一致
无障碍使用 → 包容性设计
原则的结构
好的设计原则应该:
- 可操作:能够指导具体决策
- 有区分度:不是放之四海而皆准的废话
- 易记忆:数量控制在 5-7 条
# Example: ABC 公司设计原则
## 1. 清晰优先 (Clarity First)
信息的清晰传达是最重要的。在装饰性和功能性之间,永远选择功能性。
- ✓ 使用明确的标签和说明
- ✓ 减少视觉噪音
- ✗ 为了美观牺牲可读性
## 2. 一致而非统一 (Consistent, Not Uniform)
保持核心体验的一致性,但允许根据上下文做出适当调整。
- ✓ 相同操作相同行为
- ✓ 考虑场景差异
- ✗ 机械地应用所有规则
## 3. 渐进式披露 (Progressive Disclosure)
先展示必要信息,高级选项按需展开。
- ✓ 默认展示 20% 覆盖 80% 用户
- ✓ 复杂功能分层展示
- ✗ 一次性堆砌所有选项
## 4. 包容性设计 (Inclusive Design)
为所有用户设计,包括能力不同的用户。
- ✓ 符合 WCAG 2.1 AA 标准
- ✓ 支持键盘和屏幕阅读器
- ✗ 只考虑主流用户
## 5. 性能即体验 (Performance is UX)
加载速度和响应性是用户体验的一部分。
- ✓ 组件轻量化
- ✓ 考虑弱网络环境
- ✗ 引入重型动效库
设计令牌体系
设计令牌(Design Tokens)是设计系统的原子级变量。
令牌的层级结构
┌─────────────────────────────────────────────────────────────┐
│ 设计令牌层级 │
├─────────────────────────────────────────────────────────────┤
│ │
│ Global Tokens (全局令牌) │
│ ├─ $color-blue-500: #3B82F6 │
│ ├─ $color-gray-100: #F3F4F6 │
│ └─ $spacing-4: 16px │
│ │
│ ↓ 引用 │
│ │
│ Alias Tokens (语义令牌) │
│ ├─ $color-primary: $color-blue-500 │
│ ├─ $color-background: $color-gray-100 │
│ └─ $spacing-component: $spacing-4 │
│ │
│ ↓ 引用 │
│ │
│ Component Tokens (组件令牌) │
│ ├─ $button-bg-primary: $color-primary │
│ ├─ $button-padding: $spacing-component │
│ └─ $card-background: $color-background │
│ │
└─────────────────────────────────────────────────────────────┘
定义令牌规范
// tokens/base.json - 基础色板
{
"color": {
"gray": {
"50": { "value": "#F9FAFB", "type": "color" },
"100": { "value": "#F3F4F6", "type": "color" },
"200": { "value": "#E5E7EB", "type": "color" },
"300": { "value": "#D1D5DB", "type": "color" },
"400": { "value": "#9CA3AF", "type": "color" },
"500": { "value": "#6B7280", "type": "color" },
"600": { "value": "#4B5563", "type": "color" },
"700": { "value": "#374151", "type": "color" },
"800": { "value": "#1F2937", "type": "color" },
"900": { "value": "#111827", "type": "color" }
},
"blue": {
"50": { "value": "#EFF6FF", "type": "color" },
"100": { "value": "#DBEAFE", "type": "color" },
"500": { "value": "#3B82F6", "type": "color" },
"600": { "value": "#2563EB", "type": "color" },
"700": { "value": "#1D4ED8", "type": "color" }
}
},
"spacing": {
"0": { "value": "0", "type": "dimension" },
"1": { "value": "4px", "type": "dimension" },
"2": { "value": "8px", "type": "dimension" },
"3": { "value": "12px", "type": "dimension" },
"4": { "value": "16px", "type": "dimension" },
"5": { "value": "20px", "type": "dimension" },
"6": { "value": "24px", "type": "dimension" },
"8": { "value": "32px", "type": "dimension" },
"10": { "value": "40px", "type": "dimension" },
"12": { "value": "48px", "type": "dimension" }
},
"borderRadius": {
"none": { "value": "0", "type": "dimension" },
"sm": { "value": "4px", "type": "dimension" },
"md": { "value": "6px", "type": "dimension" },
"lg": { "value": "8px", "type": "dimension" },
"xl": { "value": "12px", "type": "dimension" },
"full": { "value": "9999px", "type": "dimension" }
}
}
// tokens/semantic.json - 语义令牌
{
"color": {
"text": {
"primary": { "value": "{color.gray.900}", "type": "color" },
"secondary": { "value": "{color.gray.600}", "type": "color" },
"disabled": { "value": "{color.gray.400}", "type": "color" },
"inverse": { "value": "{color.gray.50}", "type": "color" }
},
"background": {
"primary": { "value": "#FFFFFF", "type": "color" },
"secondary": { "value": "{color.gray.50}", "type": "color" },
"elevated": { "value": "#FFFFFF", "type": "color" }
},
"border": {
"default": { "value": "{color.gray.200}", "type": "color" },
"focus": { "value": "{color.blue.500}", "type": "color" }
},
"action": {
"primary": { "value": "{color.blue.500}", "type": "color" },
"primaryHover": { "value": "{color.blue.600}", "type": "color" },
"primaryActive": { "value": "{color.blue.700}", "type": "color" }
}
}
}
令牌到代码的转换
使用 Style Dictionary 将令牌转换为多平台代码:
// style-dictionary.config.js
const StyleDictionary = require('style-dictionary');
StyleDictionary.registerTransform({
name: 'size/pxToRem',
type: 'value',
matcher: (token) => token.type === 'dimension',
transformer: (token) => {
const px = parseFloat(token.value);
return `${px / 16}rem`;
}
});
module.exports = {
source: ['tokens/**/*.json'],
platforms: {
// CSS 变量
css: {
transformGroup: 'css',
buildPath: 'build/css/',
files: [{
destination: 'variables.css',
format: 'css/variables'
}]
},
// SCSS 变量
scss: {
transformGroup: 'scss',
buildPath: 'build/scss/',
files: [{
destination: '_variables.scss',
format: 'scss/variables'
}]
},
// JavaScript 对象
js: {
transformGroup: 'js',
buildPath: 'build/js/',
files: [{
destination: 'tokens.js',
format: 'javascript/es6'
}]
},
// TypeScript
ts: {
transformGroup: 'js',
buildPath: 'build/ts/',
files: [{
destination: 'tokens.ts',
format: 'javascript/es6'
}]
}
}
};
生成的输出:
/* build/css/variables.css */
:root {
--color-gray-50: #F9FAFB;
--color-gray-100: #F3F4F6;
--color-text-primary: var(--color-gray-900);
--color-text-secondary: var(--color-gray-600);
--color-action-primary: var(--color-blue-500);
--spacing-4: 1rem;
--border-radius-md: 0.375rem;
}
// build/ts/tokens.ts
export const tokens = {
color: {
gray: {
50: '#F9FAFB',
100: '#F3F4F6',
// ...
},
text: {
primary: '#111827',
secondary: '#4B5563',
}
},
spacing: {
4: '1rem',
// ...
}
} as const;
组件库架构
组件分类体系
┌─────────────────────────────────────────────────────────────┐
│ 组件分类 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 基础组件 (Primitives) │
│ └─ 最底层、无业务逻辑的原子组件 │
│ ├─ Button, Icon, Input, Text, Box │
│ └─ 可被任何上层组件使用 │
│ │
│ 通用组件 (Common) │
│ └─ 常见的 UI 模式,跨业务通用 │
│ ├─ Card, Modal, Dropdown, Tabs, Toast │
│ └─ 由基础组件组合而成 │
│ │
│ 业务组件 (Business) │
│ └─ 特定业务场景的复合组件 │
│ ├─ UserCard, ProductTile, CommentBox │
│ └─ 包含业务逻辑和数据结构 │
│ │
│ 布局组件 (Layout) │
│ └─ 控制页面结构和响应式布局 │
│ ├─ Container, Grid, Stack, Sidebar │
│ └─ 处理间距、对齐、响应式断点 │
│ │
└─────────────────────────────────────────────────────────────┘
组件设计原则
1. 单一职责
// ✗ 职责过多的组件
<UserCard
user={user}
showFollowButton
showMessageButton
showStats
layout="horizontal"
theme="dark"
/>
// ✓ 拆分为多个单一职责组件
<Card>
<UserAvatar user={user} />
<UserInfo user={user} />
<UserActions>
<FollowButton userId={user.id} />
<MessageButton userId={user.id} />
</UserActions>
</Card>
2. 组合优于配置
// ✗ 通过 props 配置一切
<Button
icon="plus"
iconPosition="left"
loading={isLoading}
loadingText="保存中..."
size="lg"
variant="primary"
/>
// ✓ 通过组合实现灵活性
<Button size="lg" variant="primary">
{isLoading ? (
<>
<Spinner size="sm" />
<span>保存中...</span>
</>
) : (
<>
<Icon name="plus" />
<span>新建</span>
</>
)}
</Button>
3. 样式与行为分离
// Button.tsx - 组件逻辑
export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, ...props }, ref) => {
return (
<button
ref={ref}
className={cn(buttonVariants({ variant, size }), className)}
{...props}
/>
);
}
);
// Button.styles.ts - 样式定义
import { cva } from 'class-variance-authority';
export const buttonVariants = cva(
'inline-flex items-center justify-center rounded-md font-medium transition-colors focus-visible:outline-none focus-visible:ring-2',
{
variants: {
variant: {
primary: 'bg-primary text-white hover:bg-primary-hover',
secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary-hover',
outline: 'border border-input bg-transparent hover:bg-accent',
},
size: {
sm: 'h-8 px-3 text-sm',
md: 'h-10 px-4 text-sm',
lg: 'h-12 px-6 text-base',
},
},
defaultVariants: {
variant: 'primary',
size: 'md',
},
}
);
组件 API 设计规范
// 组件 Props 设计规范
// 1. 使用语义化的 prop 名称
interface ButtonProps {
variant?: 'primary' | 'secondary' | 'outline' | 'ghost' | 'danger';
size?: 'sm' | 'md' | 'lg';
// ✗ 避免使用 type(与 HTML 属性冲突)
// ✗ 避免使用缩写 var, sz
}
// 2. 布尔 props 使用正面语义
interface InputProps {
disabled?: boolean; // ✓ 默认 false
readOnly?: boolean; // ✓ 默认 false
// ✗ enabled?: boolean; // 避免双重否定
}
// 3. 事件处理器使用 on 前缀
interface ModalProps {
onClose?: () => void; // ✓
onOpenChange?: (open: boolean) => void; // ✓
// ✗ closeHandler, handleClose
}
// 4. 支持 className 和 style 覆盖
interface CardProps {
className?: string;
style?: React.CSSProperties;
// 允许用户自定义样式
}
// 5. 使用 children 而非 text props
interface BadgeProps {
children: React.ReactNode; // ✓
// ✗ text?: string;
// ✗ label?: string;
}
// 6. 提供合理的默认值
interface TooltipProps {
placement?: 'top' | 'bottom' | 'left' | 'right'; // 默认 'top'
delay?: number; // 默认 200
// 默认值在组件内部设置
}
文档体系
文档的组成
设计系统文档
├── 入门指南
│ ├── 快速开始
│ ├── 安装与配置
│ └── 设计原则
│
├── 设计基础
│ ├── 颜色系统
│ ├── 字体排版
│ ├── 间距与网格
│ ├── 图标系统
│ └── 动效规范
│
├── 组件文档
│ ├── 组件概览
│ └── 各组件详情
│ ├── 描述与用途
│ ├── 交互示例
│ ├── API 参考
│ ├── 设计指南
│ └── 可访问性
│
├── 模式库
│ ├── 表单模式
│ ├── 导航模式
│ ├── 数据展示
│ └── 反馈与提示
│
└── 资源与工具
├── Figma 资源
├── 品牌资产
└── 贡献指南
组件文档模板
# Button 按钮
按钮用于触发操作或事件,如提交表单、打开对话框或执行功能。
## 何时使用
- 当用户需要触发一个动作时
- 当需要在页面上突出一个关键操作时
## 基础用法
<ComponentDemo>
<Button>默认按钮</Button>
<Button variant="secondary">次要按钮</Button>
<Button variant="outline">描边按钮</Button>
</ComponentDemo>
## 变体
### 主要按钮 (Primary)
用于页面最重要的操作,一个页面通常只有一个主要按钮。
### 次要按钮 (Secondary)
用于次要操作,与主要按钮配合使用。
### 危险按钮 (Danger)
用于删除、移除等破坏性操作。
## 尺寸
<ComponentDemo>
<Button size="sm">小号</Button>
<Button size="md">中号</Button>
<Button size="lg">大号</Button>
</ComponentDemo>
## 状态
### 禁用状态
<ComponentDemo>
<Button disabled>禁用按钮</Button>
</ComponentDemo>
### 加载状态
<ComponentDemo>
<Button loading>加载中</Button>
</ComponentDemo>
## API
| 属性 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| variant | 'primary' \| 'secondary' \| 'outline' \| 'ghost' \| 'danger' | 'primary' | 按钮变体 |
| size | 'sm' \| 'md' \| 'lg' | 'md' | 按钮尺寸 |
| disabled | boolean | false | 是否禁用 |
| loading | boolean | false | 是否加载中 |
## 可访问性
- 使用语义化的 `<button>` 元素
- 禁用状态有明确的视觉区分
- 支持键盘操作(Enter/Space 触发)
- 聚焦状态有清晰的视觉反馈
## 设计规范
- 按钮文案使用动词或动词短语
- 文案长度建议 2-6 个字符
- 同一区域内按钮尺寸保持一致
- 主要按钮放在操作区域的右侧或底部
使用 Storybook 构建交互式文档
// Button.stories.tsx
import type { Meta, StoryObj } from '@storybook/react';
import { Button } from './Button';
const meta: Meta<typeof Button> = {
title: 'Components/Button',
component: Button,
parameters: {
layout: 'centered',
docs: {
description: {
component: '按钮用于触发操作或事件。',
},
},
},
tags: ['autodocs'],
argTypes: {
variant: {
control: 'select',
options: ['primary', 'secondary', 'outline', 'ghost', 'danger'],
description: '按钮的视觉变体',
},
size: {
control: 'radio',
options: ['sm', 'md', 'lg'],
description: '按钮的尺寸',
},
disabled: {
control: 'boolean',
description: '是否禁用',
},
loading: {
control: 'boolean',
description: '是否显示加载状态',
},
},
};
export default meta;
type Story = StoryObj<typeof Button>;
export const Primary: Story = {
args: {
children: '主要按钮',
variant: 'primary',
},
};
export const Secondary: Story = {
args: {
children: '次要按钮',
variant: 'secondary',
},
};
export const AllVariants: Story = {
render: () => (
<div className="flex gap-4">
<Button variant="primary">Primary</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="outline">Outline</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="danger">Danger</Button>
</div>
),
};
export const Sizes: Story = {
render: () => (
<div className="flex items-center gap-4">
<Button size="sm">Small</Button>
<Button size="md">Medium</Button>
<Button size="lg">Large</Button>
</div>
),
};
export const States: Story = {
render: () => (
<div className="flex gap-4">
<Button>Default</Button>
<Button disabled>Disabled</Button>
<Button loading>Loading</Button>
</div>
),
};
版本管理与发布
语义化版本控制
版本号格式:MAJOR.MINOR.PATCH
MAJOR (主版本)
└─ 不兼容的 API 变更
例:组件 props 重命名、移除组件
MINOR (次版本)
└─ 向后兼容的功能新增
例:新增组件、新增 props
PATCH (补丁版本)
└─ 向后兼容的问题修复
例:样式修复、bug 修复
变更日志规范
# Changelog
## [2.1.0] - 2024-12-25
### ✨ New Features
- **Button**: 新增 `loading` 状态和 `loadingText` 属性
- **Modal**: 新增 `size` 属性,支持 sm/md/lg/xl 四种尺寸
### 🐛 Bug Fixes
- **Input**: 修复 disabled 状态下仍可聚焦的问题
- **Dropdown**: 修复在移动端点击外部无法关闭的问题
### 💄 Styles
- **全局**: 调整主色调从 #3B82F6 到 #2563EB
- **Button**: 优化 hover 状态的过渡动画
### ⚠️ Deprecations
- **Alert**: `type` 属性已废弃,请使用 `variant`
## [2.0.0] - 2024-12-01
### 💥 Breaking Changes
- **Button**: `type` 属性重命名为 `variant`
- **Icon**: 移除 `size` 属性,改用 CSS 控制尺寸
- **tokens**: 颜色令牌命名从 camelCase 改为 kebab-case
发布流程
# 1. 创建发布分支
git checkout -b release/2.1.0
# 2. 更新版本号
npm version minor
# 3. 更新 CHANGELOG
# 手动编辑 CHANGELOG.md
# 4. 构建并测试
npm run build
npm run test
npm run test:visual
# 5. 发布到 npm
npm publish
# 6. 合并到 main
git checkout main
git merge release/2.1.0
# 7. 打标签
git tag v2.1.0
git push origin v2.1.0
# 8. 发布文档
npm run deploy:docs
团队协作流程
组件贡献流程
┌────────────────────────────────────────────────────────────────┐
│ 组件贡献流程 │
├────────────────────────────────────────────────────────────────┤
│ │
│ 1. 提案阶段 │
│ ├─ 提交 RFC(组件设计提案) │
│ ├─ 团队评审(设计 + 开发) │
│ └─ 确定 API 和设计规范 │
│ │
│ 2. 设计阶段 │
│ ├─ 设计师在 Figma 中创建组件 │
│ ├─ 设计评审 │
│ └─ 交付设计规范文档 │
│ │
│ 3. 开发阶段 │
│ ├─ 实现组件代码 │
│ ├─ 编写单元测试 │
│ ├─ 编写 Storybook stories │
│ └─ 代码评审 │
│ │
│ 4. 文档阶段 │
│ ├─ 编写使用文档 │
│ ├─ 添加示例代码 │
│ └─ 更新 CHANGELOG │
│ │
│ 5. 发布阶段 │
│ ├─ QA 验收 │
│ ├─ 发布新版本 │
│ └─ 通知用户更新 │
│ │
└────────────────────────────────────────────────────────────────┘
设计与开发同步
Figma (设计) 代码 (开发)
─────────────────────────────────────────────
设计令牌 tokens/
├─ Colors ├─ colors.json
├─ Typography ├─ typography.json
└─ Spacing └─ spacing.json
│ │
▼ ▼
Tokens Studio Style Dictionary
(Figma 插件) (构建工具)
│ │
└──────── 同步 ────────────────┘
│
▼
自动化 CI/CD
检测变更并更新
总结
建立一个成功的设计系统需要:
- 明确的设计原则:指导所有设计决策
- 完善的令牌体系:确保视觉一致性
- 高质量的组件库:可复用、可组合、可访问
- 详尽的文档:降低使用门槛
- 规范的版本管理:平滑升级体验
- 顺畅的协作流程:设计与开发高效同步
设计系统是一个持续演进的产品,需要长期投入和维护。
延伸阅读
- Figma Tokens 与变量同步 - 设计侧的详细实践
- 组件库架构设计 - 代码层面的深入探讨
- Design Tokens 规范 - 令牌的深度讲解


