📖 核心概念
- 设计系统概述与价值
- Design Tokens:颜色、间距、排版
- 组件规范与文档
- 主题系统架构
- 设计系统工具链
- 版本管理与变更日志
💻 代码实现
Design Tokens
✅ css
/* ===== Design Tokens ===== */
:root {
/* 颜色系统 - 语义化命名 */
--color-primary-50: #ecfeff;
--color-primary-100: #cffafe;
--color-primary-200: #a5f3fc;
--color-primary-300: #67e8f9;
--color-primary-400: #22d3ee;
--color-primary-500: #06b6d4;
--color-primary-600: #0891b2;
--color-primary-700: #0e7490;
--color-primary-800: #155e75;
--color-primary-900: #164e63;
/* 语义色 */
--color-bg-primary: #0f172a;
--color-bg-secondary: #1e293b;
--color-bg-elevated: #334155;
--color-text-primary: #f1f5f9;
--color-text-secondary: #94a3b8;
--color-text-muted: #64748b;
--color-border-default: #334155;
--color-border-focus: #06b6d4;
--color-success: #10b981;
--color-warning: #f59e0b;
--color-error: #ef4444;
--color-info: #06b6d4;
/* 间距系统 - 4px基数 */
--space-0: 0;
--space-1: 0.25rem; /* 4px */
--space-2: 0.5rem; /* 8px */
--space-3: 0.75rem; /* 12px */
--space-4: 1rem; /* 16px */
--space-5: 1.25rem; /* 20px */
--space-6: 1.5rem; /* 24px */
--space-8: 2rem; /* 32px */
--space-10: 2.5rem; /* 40px */
--space-12: 3rem; /* 48px */
--space-16: 4rem; /* 64px */
/* 排版系统 */
--font-sans: 'Inter', system-ui, -apple-system, sans-serif;
--font-mono: 'Fira Code', 'Consolas', monospace;
--font-size-xs: 0.75rem;
--font-size-sm: 0.875rem;
--font-size-base: 1rem;
--font-size-lg: 1.125rem;
--font-size-xl: 1.25rem;
--font-size-2xl: 1.5rem;
--font-size-3xl: 1.875rem;
--font-size-4xl: 2.25rem;
--line-height-tight: 1.25;
--line-height-normal: 1.5;
--line-height-relaxed: 1.75;
/* 圆角 */
--radius-sm: 4px;
--radius-md: 8px;
--radius-lg: 12px;
--radius-xl: 16px;
--radius-full: 9999px;
/* 阴影 */
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3);
--shadow-md: 0 4px 6px rgba(0, 0, 0, 0.3);
--shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.3);
--shadow-xl: 0 20px 25px rgba(0, 0, 0, 0.3);
/* 过渡 */
--transition-fast: 150ms ease;
--transition-normal: 250ms ease;
--transition-slow: 350ms ease;
--transition-spring: 500ms cubic-bezier(0.34, 1.56, 0.64, 1);
}
组件规范与主题
✅ tsx
// 组件规范:Button
import { forwardRef } from 'react';
import styles from './Button.module.css';
export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
variant?: 'primary' | 'secondary' | 'ghost' | 'danger';
size?: 'sm' | 'md' | 'lg';
loading?: boolean;
icon?: ReactNode;
fullWidth?: boolean;
}
export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
({ variant = 'primary', size = 'md', loading, icon, children, disabled, ...props }, ref) => {
return (
<button
ref={ref}
className={styles.button}
data-variant={variant}
data-size={size}
data-loading={loading}
disabled={disabled || loading}
{...props}
>
{loading && <Spinner className={styles.spinner} />}
{!loading && icon && <span className={styles.icon}>{icon}</span>}
{children && <span className={styles.label}>{children}</span>}
</button>
);
}
);
/* Button.module.css */
/*
.button {
display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2);
font-family: var(--font-sans); font-weight: 500; border: none; cursor: pointer;
transition: all var(--transition-fast); border-radius: var(--radius-md);
}
.button[data-size="sm"] { padding: var(--space-1) var(--space-3); font-size: var(--font-size-sm); }
.button[data-size="md"] { padding: var(--space-2) var(--space-4); font-size: var(--font-size-base); }
.button[data-size="lg"] { padding: var(--space-3) var(--space-6); font-size: var(--font-size-lg); }
.button[data-variant="primary"] { background: var(--color-primary-500); color: white; }
.button[data-variant="primary"]:hover { background: var(--color-primary-600); }
.button[data-variant="secondary"] { background: var(--color-bg-elevated); color: var(--color-text-primary); }
.button[data-variant="ghost"] { background: transparent; color: var(--color-text-secondary); }
.button[data-variant="danger"] { background: var(--color-error); color: white; }
.button:disabled { opacity: 0.5; cursor: not-allowed; }
*/
// 主题切换系统
import { createContext, useContext } from 'react';
type Theme = 'light' | 'dark' | 'system';
const ThemeContext = createContext<{ theme: Theme; setTheme: (t: Theme) => void }>({} as any);
function ThemeProvider({ children }: { children: ReactNode }) {
const [theme, setTheme] = useLocalStorage<Theme>('theme', 'system');
const resolvedTheme = theme === 'system'
? window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
: theme;
useEffect(() => {
document.documentElement.setAttribute('data-theme', resolvedTheme);
}, [resolvedTheme]);
return <ThemeContext.Provider value={{ theme, setTheme }}>{children}</ThemeContext.Provider>;
}
🎯 练习任务
- 1 设计一套完整的Design Tokens,包含颜色、间距、排版、阴影
- 2 创建一个Button组件,支持4种变体和3种尺寸
- 3 实现主题切换系统,支持亮色/暗色/跟随系统
- 4 使用Storybook为组件库编写文档
🏆 成就解锁
设计系统架构师 — 构建可扩展的设计系统,统一产品视觉语言