AI 辅助的设计系统主题扩展:从品牌色到完整配色方案的智能推导

cover

一、主题扩展的"色板困境":设计系统的规模化痛点

设计系统(Design System)的核心价值是一致性,但一致性不意味着单一主题。企业级产品通常需要支持多品牌(白标产品)、暗色模式、高对比度模式等多种主题。每个主题需要从品牌主色推导出完整的色板:主色、辅色、背景色、文字色、边框色、状态色(成功/警告/错误/信息),以及每个颜色的多个层级(50-950)。

手动创建一个完整的主题色板需要 2-4 小时,且不同设计师创建的色板风格可能不一致。AI 辅助的主题扩展,核心思路是:输入一个品牌主色,自动推导出完整的配色方案,保证色彩和谐、对比度合规、层级分明。

二、AI 主题扩展的架构与色彩推导机制

flowchart TD
    A[品牌主色输入] --> B[色彩空间转换: HSL/OKLCH]
    B --> C[AI 推导配色方案]
    C --> D[主色层级: 50-950]
    C --> E[辅色推导: 互补/类似/三角]
    C --> F[中性色推导: 冷灰/暖灰]
    C --> G[状态色推导: 成功/警告/错误]
    D & E & F & G --> H[对比度校验: WCAG AA/AAA]
    H --> I{对比度不达标?}
    I -->|是| J[自动微调亮度]
    I -->|否| K[生成 Design Token]
    J --> H
    K --> L[输出: CSS 变量 / JSON / Figma Token]

三、AI 主题扩展的代码实现

3.1 色彩推导引擎

interface ColorPalette {
  primary: ColorScale;      // 主色层级 50-950
  secondary: ColorScale;    // 辅色层级
  neutral: ColorScale;      // 中性色层级
  success: ColorScale;      // 成功色层级
  warning: ColorScale;      // 警告色层级
  error: ColorScale;        // 错误色层级
}

interface ColorScale {
  50: string; 100: string; 200: string; 300: string;
  400: string; 500: string; 600: string; 700: string;
  800: string; 900: string; 950: string;
}

class ThemeExpander {
  /**
   * 从品牌主色推导完整配色方案
   * 使用 OKLCH 色彩空间,感知均匀性优于 HSL
   */
  expandFromPrimary(primaryHex: string): ColorPalette {
    const primary = this.hexToOKLCH(primaryHex);

    return {
      primary: this.generateScale(primary),
      secondary: this.generateScale(this.deriveSecondary(primary)),
      neutral: this.generateScale(this.deriveNeutral(primary)),
      success: this.generateScale(this.deriveSuccess()),
      warning: this.generateScale(this.deriveWarning()),
      error: this.generateScale(this.deriveError()),
    };
  }

  /**
   * 生成颜色层级:从浅到深的 11 级色阶
   * 核心逻辑:固定色相,线性插值亮度和微调色度
   */
  private generateScale(baseColor: OKLCHColor): ColorScale {
    const { h, c } = baseColor;
    // 亮度从 0.97(最浅)到 0.15(最深)
    // 色度在中段最高,两端降低
    const levels = [0.97, 0.94, 0.88, 0.80, 0.70, 0.60,
                    0.50, 0.40, 0.30, 0.22, 0.15];

    const scale: any = {};
    const scaleKeys = [50, 100, 200, 300, 400, 500,
                       600, 700, 800, 900, 950];

    levels.forEach((l, i) => {
      // 色度在中段(500)最高,两端降低
      const chromaFactor = 1 - Math.abs(l - 0.6) / 0.5;
      const adjustedC = c * Math.max(0.1, chromaFactor);
      const color = { l, c: adjustedC, h };
      scale[scaleKeys[i]] = this.oklchToHex(color);
    });

    return scale as ColorScale;
  }

  /**
   * 推导辅色:使用互补色(色相偏移 180°)
   */
  private deriveSecondary(primary: OKLCHColor): OKLCHColor {
    return { ...primary, h: (primary.h + 180) % 360 };
  }

  /**
   * 推导中性色:降低色度,保留微量色相
   * 避免纯灰色显得"死板"
   */
  private deriveNeutral(primary: OKLCHColor): OKLCHColor {
    return { l: 0.5, c: primary.c * 0.05, h: primary.h };
  }

  /**
   * WCAG 对比度校验与自动微调
   */
  private ensureContrast(
    foreground: string, background: string,
    level: 'AA' | 'AAA' = 'AA'
  ): string {
    const minRatio = level === 'AA' ? 4.5 : 7;
    let fg = this.hexToOKLCH(foreground);
    const bg = this.hexToOKLCH(background);
    let ratio = this.contrastRatio(fg, bg);

    // 对比度不足时,微调前景色亮度
    while (ratio < minRatio && fg.l > 0.05 && fg.l < 0.95) {
      fg = fg.l > bg.l
        ? { ...fg, l: fg.l + 0.02 }  // 前景更亮
        : { ...fg, l: fg.l - 0.02 }; // 前景更暗
      ratio = this.contrastRatio(fg, bg);
    }

    return this.oklchToHex(fg);
  }

  private contrastRatio(fg: OKLCHColor, bg: OKLCHColor): number {
    const l1 = fg.l, l2 = bg.l;
    const lighter = Math.max(l1, l2);
    const darker = Math.min(l1, l2);
    return (lighter + 0.05) / (darker + 0.05);
  }
}

3.2 Design Token 输出

class DesignTokenExporter {
  /**
   * 将配色方案导出为 CSS 变量
   */
  toCSSVariables(palette: ColorPalette): string {
    const lines: string[] = [':root {'];
    for (const [name, scale] of Object.entries(palette)) {
      for (const [level, color] of Object.entries(scale)) {
        lines.push(`  --color-${name}-${level}: ${color};`);
      }
    }
    lines.push('}');
    return lines.join('\n');
  }

  /**
   * 导出为 JSON Token(兼容 Style Dictionary)
   */
  toJSONTokens(palette: ColorPalette): object {
    const tokens: any = { color: {} };
    for (const [name, scale] of Object.entries(palette)) {
      tokens.color[name] = {};
      for (const [level, color] of Object.entries(scale)) {
        tokens.color[name][level] = {
          value: color,
          type: 'color',
          description: `${name} ${level}`
        };
      }
    }
    return tokens;
  }
}

四、AI 主题扩展的边界分析与架构权衡

色彩和谐的主观性。AI 推导的配色方案基于色彩理论(互补色、类似色),但色彩和谐是主观的——不同文化和品牌对色彩的偏好不同。AI 生成的方案应作为起点,设计师需要根据品牌调性微调。

OKLCH 的浏览器支持。OKLCH 色彩空间在 CSS 中的支持需要 color() 函数,部分旧浏览器不支持。输出 CSS 变量时,建议同时提供 OKLCH 和 sRGB(HEX)两种格式,确保兼容性。

暗色模式的推导复杂度。暗色模式不是简单地反转亮度——暗色背景上的文字需要降低对比度以减少视觉疲劳,状态色在暗色背景上需要提高饱和度以保持辨识度。AI 推导暗色主题时需要额外的调整规则。

适用边界:AI 主题扩展最适合需要快速生成多主题的场景(白标产品、多品牌支持)。对于单一品牌、主题固定的项目,手动调色可以更精确地匹配品牌调性。

五、总结

AI 辅助的设计系统主题扩展通过色彩空间转换和层级推导,从单一品牌色自动生成完整的配色方案。OKLCH 色彩空间提供感知均匀的层级插值,WCAG 对比度校验确保可访问性合规。落地时需关注色彩和谐的主观性、OKLCH 的浏览器兼容性、以及暗色模式的特殊调整规则。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐