原子设计:夸克Skill atomic-design-quarks

原子设计:夸克技能专注于使用原子设计方法论中的夸克级别来构建和维护设计系统的基础。它包括定义和管理设计令牌(如颜色、间距、字体大小、阴影等原始值),并将它们导出为CSS自定义属性,以实现样式一致性和主题支持。此技能适用于前端开发中的设计系统建设,确保可维护性和可扩展性,适用于创建可主题化的组件库、大型代码库一致性维护以及多品牌应用开发。关键词:原子设计、夸克、设计令牌、CSS变量、前端开发、设计系统、样式一致性、主题化。

前端开发 0 次安装 0 次浏览 更新于 3/25/2026

名称: 原子设计-夸克 用户可调用: false 描述: 在设计与设计令牌、CSS自定义属性以及构成原子基础以下的原始值时使用。夸克是亚原子构建块。 允许工具:

  • Bash
  • 读取
  • 写入
  • 编辑
  • Glob
  • Grep

原子设计:夸克

掌握创建和组织夸克——构成设计系统基础的亚原子设计令牌和原始值。夸克是原子消费的最小构建块。

什么是夸克?

夸克扩展了布拉德·弗罗斯特的原子设计方法论,添加了原子以下的级别。原子是最小的UI组件,夸克是最小的设计值——构建原子的原材料。

夸克是:

  • 原始值:颜色、间距单位、字体大小、阴影
  • 非可视化:它们本身不渲染任何内容
  • 设计令牌:定义设计语言的命名常量
  • 由原子消费:原子导入并使用夸克进行样式设计

夸克 vs 原子

方面 夸克 原子
性质 值/令牌 UI组件
渲染 无(CSS变量、常量) 可视化元素
示例 --color-primary-500spacing.md 按钮、输入、标签
导入 无(基础级别) 仅夸克
目的 定义设计语言 实现设计语言

常见夸克类型

颜色令牌

// 夸克/颜色.ts
export const colors = {
  // 品牌颜色
  primary: {
    50: '#e3f2fd',
    100: '#bbdefb',
    200: '#90caf9',
    300: '#64b5f6',
    400: '#42a5f5',
    500: '#2196f3', // 主色
    600: '#1e88e5',
    700: '#1976d2',
    800: '#1565c0',
    900: '#0d47a1',
  },

  // 语义颜色
  success: {
    light: '#4caf50',
    main: '#2e7d32',
    dark: '#1b5e20',
  },
  warning: {
    light: '#ff9800',
    main: '#ed6c02',
    dark: '#e65100',
  },
  danger: {
    light: '#ef5350',
    main: '#d32f2f',
    dark: '#c62828',
  },

  // 中性颜色
  neutral: {
    0: '#ffffff',
    50: '#fafafa',
    100: '#f5f5f5',
    200: '#eeeeee',
    300: '#e0e0e0',
    400: '#bdbdbd',
    500: '#9e9e9e',
    600: '#757575',
    700: '#616161',
    800: '#424242',
    900: '#212121',
  },
} as const;

export type ColorScale = keyof typeof colors;
export type PrimaryShade = keyof typeof colors.primary;

间距令牌

// 夸克/间距.ts
export const spacing = {
  px: '1px',
  0: '0',
  0.5: '0.125rem', // 2px
  1: '0.25rem',    // 4px
  1.5: '0.375rem', // 6px
  2: '0.5rem',     // 8px
  2.5: '0.625rem', // 10px
  3: '0.75rem',    // 12px
  3.5: '0.875rem', // 14px
  4: '1rem',       // 16px
  5: '1.25rem',    // 20px
  6: '1.5rem',     // 24px
  7: '1.75rem',    // 28px
  8: '2rem',       // 32px
  9: '2.25rem',    // 36px
  10: '2.5rem',    // 40px
  12: '3rem',      // 48px
  14: '3.5rem',    // 56px
  16: '4rem',      // 64px
  20: '5rem',      // 80px
  24: '6rem',      // 96px
} as const;

// 语义间距别名
export const spacingAliases = {
  none: spacing[0],
  xs: spacing[1],
  sm: spacing[2],
  md: spacing[4],
  lg: spacing[6],
  xl: spacing[8],
  '2xl': spacing[12],
  '3xl': spacing[16],
} as const;

排版令牌

// 夸克/排版.ts
export const fontFamily = {
  sans: [
    'Inter',
    'ui-sans-serif',
    'system-ui',
    '-apple-system',
    'BlinkMacSystemFont',
    'Segoe UI',
    'Roboto',
    'sans-serif',
  ].join(', '),
  serif: [
    'Georgia',
    'Cambria',
    'Times New Roman',
    'Times',
    'serif',
  ].join(', '),
  mono: [
    'Fira Code',
    'ui-monospace',
    'SFMono-Regular',
    'Menlo',
    'Monaco',
    'Consolas',
    'monospace',
  ].join(', '),
} as const;

export const fontSize = {
  xs: '0.75rem',    // 12px
  sm: '0.875rem',   // 14px
  base: '1rem',     // 16px
  lg: '1.125rem',   // 18px
  xl: '1.25rem',    // 20px
  '2xl': '1.5rem',  // 24px
  '3xl': '1.875rem', // 30px
  '4xl': '2.25rem', // 36px
  '5xl': '3rem',    // 48px
  '6xl': '3.75rem', // 60px
} as const;

export const fontWeight = {
  thin: 100,
  extralight: 200,
  light: 300,
  normal: 400,
  medium: 500,
  semibold: 600,
  bold: 700,
  extrabold: 800,
  black: 900,
} as const;

export const lineHeight = {
  none: 1,
  tight: 1.25,
  snug: 1.375,
  normal: 1.5,
  relaxed: 1.625,
  loose: 2,
} as const;

export const letterSpacing = {
  tighter: '-0.05em',
  tight: '-0.025em',
  normal: '0em',
  wide: '0.025em',
  wider: '0.05em',
  widest: '0.1em',
} as const;

边框令牌

// 夸克/边框.ts
export const borderRadius = {
  none: '0',
  sm: '0.125rem',   // 2px
  DEFAULT: '0.25rem', // 4px
  md: '0.375rem',   // 6px
  lg: '0.5rem',     // 8px
  xl: '0.75rem',    // 12px
  '2xl': '1rem',    // 16px
  '3xl': '1.5rem',  // 24px
  full: '9999px',
} as const;

export const borderWidth = {
  DEFAULT: '1px',
  0: '0',
  2: '2px',
  4: '4px',
  8: '8px',
} as const;

阴影令牌

// 夸克/阴影.ts
export const shadows = {
  none: 'none',
  sm: '0 1px 2px 0 rgb(0 0 0 / 0.05)',
  DEFAULT: '0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)',
  md: '0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)',
  lg: '0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)',
  xl: '0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)',
  '2xl': '0 25px 50px -12px rgb(0 0 0 / 0.25)',
  inner: 'inset 0 2px 4px 0 rgb(0 0 0 / 0.05)',
} as const;

// 焦点环阴影
export const focusRings = {
  primary: '0 0 0 3px rgba(33, 150, 243, 0.4)',
  danger: '0 0 0 3px rgba(239, 83, 80, 0.4)',
  success: '0 0 0 3px rgba(76, 175, 80, 0.4)',
} as const;

动画令牌

// 夸克/动画.ts
export const duration = {
  instant: '0ms',
  fast: '100ms',
  normal: '200ms',
  slow: '300ms',
  slower: '500ms',
} as const;

export const easing = {
  linear: 'linear',
  in: 'cubic-bezier(0.4, 0, 1, 1)',
  out: 'cubic-bezier(0, 0, 0.2, 1)',
  inOut: 'cubic-bezier(0.4, 0, 0.2, 1)',
  bounce: 'cubic-bezier(0.68, -0.55, 0.265, 1.55)',
} as const;

export const transitions = {
  none: 'none',
  all: `all ${duration.normal} ${easing.inOut}`,
  colors: `background-color, border-color, color, fill, stroke ${duration.normal} ${easing.inOut}`,
  opacity: `opacity ${duration.normal} ${easing.inOut}`,
  shadow: `box-shadow ${duration.normal} ${easing.inOut}`,
  transform: `transform ${duration.normal} ${easing.inOut}`,
} as const;

断点令牌

// 夸克/断点.ts
export const breakpoints = {
  xs: '320px',
  sm: '640px',
  md: '768px',
  lg: '1024px',
  xl: '1280px',
  '2xl': '1536px',
} as const;

// 媒体查询助手
export const mediaQueries = {
  xs: `@media (min-width: ${breakpoints.xs})`,
  sm: `@media (min-width: ${breakpoints.sm})`,
  md: `@media (min-width: ${breakpoints.md})`,
  lg: `@media (min-width: ${breakpoints.lg})`,
  xl: `@media (min-width: ${breakpoints.xl})`,
  '2xl': `@media (min-width: ${breakpoints['2xl']})`,
} as const;

Z-索引令牌

// 夸克/z-index.ts
export const zIndex = {
  hide: -1,
  base: 0,
  raised: 1,
  dropdown: 1000,
  sticky: 1100,
  fixed: 1200,
  overlay: 1300,
  modal: 1400,
  popover: 1500,
  tooltip: 1600,
  toast: 1700,
} as const;

CSS自定义属性

将夸克导出为CSS自定义属性以进行运行时主题化。

// 夸克/css-variables.ts
import { colors, spacing, fontSize, fontFamily } from './index';

export function generateCSSVariables(): string {
  const lines: string[] = [':root {'];

  // 颜色
  Object.entries(colors).forEach(([category, shades]) => {
    if (typeof shades === 'object') {
      Object.entries(shades).forEach(([shade, value]) => {
        lines.push(`  --color-${category}-${shade}: ${value};`);
      });
    }
  });

  // 间距
  Object.entries(spacing).forEach(([key, value]) => {
    const sanitizedKey = key.replace('.', '_');
    lines.push(`  --spacing-${sanitizedKey}: ${value};`);
  });

  // 排版
  Object.entries(fontSize).forEach(([key, value]) => {
    lines.push(`  --font-size-${key}: ${value};`);
  });

  Object.entries(fontFamily).forEach(([key, value]) => {
    lines.push(`  --font-family-${key}: ${value};`);
  });

  lines.push('}');
  return lines.join('
');
}

生成的CSS

/* 夸克/variables.css - 生成输出 */
:root {
  /* 颜色 - 主色 */
  --color-primary-50: #e3f2fd;
  --color-primary-100: #bbdefb;
  --color-primary-500: #2196f3;
  --color-primary-900: #0d47a1;

  /* 颜色 - 中性色 */
  --color-neutral-0: #ffffff;
  --color-neutral-100: #f5f5f5;
  --color-neutral-900: #212121;

  /* 间距 */
  --spacing-0: 0;
  --spacing-1: 0.25rem;
  --spacing-2: 0.5rem;
  --spacing-4: 1rem;
  --spacing-8: 2rem;

  /* 排版 */
  --font-size-xs: 0.75rem;
  --font-size-sm: 0.875rem;
  --font-size-base: 1rem;
  --font-size-lg: 1.125rem;

  --font-family-sans: Inter, ui-sans-serif, system-ui, sans-serif;
  --font-family-mono: Fira Code, ui-monospace, monospace;

  /* 边框 */
  --border-radius-sm: 0.125rem;
  --border-radius-md: 0.375rem;
  --border-radius-lg: 0.5rem;
  --border-radius-full: 9999px;

  /* 阴影 */
  --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
  --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1);
  --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1);

  /* 过渡 */
  --duration-fast: 100ms;
  --duration-normal: 200ms;
  --duration-slow: 300ms;
  --easing-in-out: cubic-bezier(0.4, 0, 0.2, 1);
}

目录结构

推荐结构

src/
  夸克/                    # 设计令牌
    index.ts                 # 桶导出
    colors.ts
    spacing.ts
    typography.ts
    borders.ts
    shadows.ts
    animations.ts
    breakpoints.ts
    z-index.ts
    css-variables.ts         # CSS自定义属性生成器
    variables.css            # 生成的CSS文件
  组件/
    原子/                   # 消费夸克的原子
      按钮/
      输入/
    分子/
    有机体/
    模板/
    页面/

索引桶导出

// 夸克/index.ts
export * from './colors';
export * from './spacing';
export * from './typography';
export * from './borders';
export * from './shadows';
export * from './animations';
export * from './breakpoints';
export * from './z-index';

在原子中使用夸克

CSS-in-JS (styled-components/emotion)

// 原子/按钮/按钮.tsx
import styled from 'styled-components';
import { colors, spacing, fontSize, borderRadius, transitions } from '@/夸克';

export const Button = styled.button<{ variant?: 'primary' | 'secondary' }>`
  padding: ${spacing[2]} ${spacing[4]};
  font-size: ${fontSize.base};
  border-radius: ${borderRadius.md};
  transition: ${transitions.colors};

  ${({ variant = 'primary' }) =>
    variant === 'primary'
      ? `
        background-color: ${colors.primary[500]};
        color: ${colors.neutral[0]};

        &:hover {
          background-color: ${colors.primary[600]};
        }
      `
      : `
        background-color: transparent;
        color: ${colors.primary[500]};
        border: 1px solid ${colors.primary[500]};

        &:hover {
          background-color: ${colors.primary[50]};
        }
      `}
`;

CSS模块与变量

// 原子/按钮/按钮.tsx
import styles from './按钮.module.css';

export const Button = ({ variant = 'primary', children }) => (
  <button className={`${styles.button} ${styles[variant]}`}>
    {children}
  </button>
);
/* 原子/按钮/按钮.module.css */
.button {
  padding: var(--spacing-2) var(--spacing-4);
  font-size: var(--font-size-base);
  border-radius: var(--border-radius-md);
  transition: var(--duration-normal) var(--easing-in-out);
}

.primary {
  background-color: var(--color-primary-500);
  color: var(--color-neutral-0);
}

.primary:hover {
  background-color: var(--color-primary-600);
}

.secondary {
  background-color: transparent;
  color: var(--color-primary-500);
  border: 1px solid var(--color-primary-500);
}

Tailwind CSS集成

// tailwind.config.js
const { colors, spacing, fontSize, borderRadius } = require('./src/夸克');

module.exports = {
  theme: {
    colors,
    spacing,
    fontSize,
    borderRadius,
  },
};

使用夸克进行主题化

暗黑模式支持

// 夸克/主题.ts
import { colors } from './colors';

export const lightTheme = {
  background: colors.neutral[0],
  foreground: colors.neutral[900],
  muted: colors.neutral[100],
  mutedForeground: colors.neutral[500],
  primary: colors.primary[500],
  primaryForeground: colors.neutral[0],
};

export const darkTheme = {
  background: colors.neutral[900],
  foreground: colors.neutral[0],
  muted: colors.neutral[800],
  mutedForeground: colors.neutral[400],
  primary: colors.primary[400],
  primaryForeground: colors.neutral[900],
};

export type Theme = typeof lightTheme;

CSS变量主题化

/* 夸克/主题-亮.css */
:root {
  --background: var(--color-neutral-0);
  --foreground: var(--color-neutral-900);
  --muted: var(--color-neutral-100);
  --primary: var(--color-primary-500);
}

/* 夸克/主题-暗.css */
[data-theme="dark"] {
  --background: var(--color-neutral-900);
  --foreground: var(--color-neutral-0);
  --muted: var(--color-neutral-800);
  --primary: var(--color-primary-400);
}

最佳实践

1. 使用语义名称

// 好: 语义命名
export const colors = {
  primary: { ... },
  danger: { ... },
  success: { ... },
};

// 坏: 原始颜色名称
export const colors = {
  blue: { ... },
  red: { ... },
  green: { ... },
};

2. 一致的尺度

// 好: 一致的尺度模式
export const colors = {
  primary: { 50, 100, 200, 300, 400, 500, 600, 700, 800, 900 },
  secondary: { 50, 100, 200, 300, 400, 500, 600, 700, 800, 900 },
};

// 坏: 不一致的尺度
export const colors = {
  primary: { light, medium, dark },
  secondary: { 100, 500, 900 },
};

3. 类型安全

// 好: 类型安全的令牌
export const spacing = { ... } as const;
export type SpacingKey = keyof typeof spacing;

function getSpacing(key: SpacingKey): string {
  return spacing[key];
}

// 坏: 非类型化字符串
function getSpacing(key: string): string {
  return spacing[key]; // 无类型检查
}

4. 单一来源

// 好: 夸克作为唯一来源
// 所有组件从夸克导入
import { colors } from '@/夸克';

// 坏: 重复值
const Button = styled.button`
  color: #2196f3; // 硬编码,非夸克!
`;

5. 文档化

// 好: 文档化您的令牌
/**
 * 主色尺度
 * 使用 500 表示默认主色操作
 * 使用 600+ 表示悬停/活动状态
 * 使用 100-400 表示背景/强调
 */
export const primary = { ... };

要避免的反模式

1. 夸克带有逻辑

// 坏: 夸克应为纯值
export const getColor = (isDark: boolean) =>
  isDark ? '#ffffff' : '#000000';

// 好: 纯值,逻辑在组件/主题中
export const colors = {
  light: { text: '#000000' },
  dark: { text: '#ffffff' },
};

2. 组件特定令牌

// 坏: 特定组件的令牌
export const buttonPrimaryBackground = '#2196f3';

// 好: 通用语义令牌
export const colors = {
  primary: { 500: '#2196f3' },
};

3. 令牌过多

// 坏: 每个可能值的令牌
export const spacing = {
  1: '1px',
  2: '2px',
  3: '3px',
  4: '4px',
  5: '5px',
  // ... 100 多个值
};

// 好: 深思熟虑、可用的尺度
export const spacing = {
  1: '0.25rem',
  2: '0.5rem',
  4: '1rem',
  6: '1.5rem',
  8: '2rem',
};

何时使用此技能

  • 为新设计系统设置设计令牌
  • 将现有CSS变量组织为结构化系统
  • 创建可主题化的组件库
  • 确保大型代码库的一致性
  • 构建白标签或多品牌应用程序
  • 从硬编码值迁移到设计令牌

相关技能

  • 原子设计基础 - 核心方法论概述
  • 原子设计原子 - 创建消费夸克的原子组件
  • 原子设计集成 - 框架特定实现模式

资源

文档

工具