You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Material Design Color Utilities生成颜色异常:黑色变深紫的解决方法

问题描述

我在项目中使用Material Design Color Utilities包创建基于主色的动态颜色主题,指定主色为#000000(黑色),通过themeFromSourceColor生成主题后,却得到深紫色#984061作为主色。实现代码如下:

import { argbFromHex, hexFromArgb, TonalPalette, themeFromSourceColor, applyTheme, Theme } from "@material/material-color-utilities";

const baseColors = {
  primary: '#000000',
  secondary: '#FCE800',
  tertiary: '#00BFFF',
  error: '#F00F3E',
  neutral: '#6F7B80',
  neutralVariant: '#7B7768'
};

const createTheme = (): Theme => {
  const primaryArgb = argbFromHex(baseColors['primary']);
  const secondaryArgb = argbFromHex(baseColors['secondary']);
  const tertiaryArgb = argbFromHex(baseColors['tertiary']);
  const errorArgb = argbFromHex(baseColors['error']);
  const neutralArgb = argbFromHex(baseColors['neutral']);
  const neutralVariantArgb = argbFromHex(baseColors['neutralVariant']);

  const theme = themeFromSourceColor(primaryArgb);

  return {
    source: primaryArgb,
    schemes: theme.schemes,
    palettes: {
      primary: TonalPalette.fromInt(primaryArgb),
      secondary: TonalPalette.fromInt(secondaryArgb),
      tertiary: TonalPalette.fromInt(tertiaryArgb),
      neutral: TonalPalette.fromInt(neutralArgb),
      neutralVariant: TonalPalette.fromInt(neutralVariantArgb),
      error: TonalPalette.fromInt(errorArgb),
    },
    customColors: [],
  };
};
/*Overwrite mui system colors*/
const applyThemeVars = (root: HTMLElement, isDarkMode: boolean, theme: any) => {
  const style = root.style;
  const colors = isDarkMode ? theme.schemes.dark : theme.schemes.light;
  Object.entries(colors.props).forEach(([key, value]) => {
    const hexColor = hexFromArgb(value as number);
    style.setProperty(`--md-sys-color-${key}`, hexColor);
  });
};

const applyCustomTheme = (isDarkMode: boolean) => {
  const generatedTheme = createTheme();
  applyThemeVars(document.documentElement, isDarkMode, generatedTheme);
  applyTheme(generatedTheme, { target: document.documentElement, dark: isDarkMode });
};

export const ThemeHelper = () => {
  return {
    applyCustomTheme,
  };
};

const themeHelper = ThemeHelper();
export default themeHelper;
原因解析

themeFromSourceColor的核心逻辑是基于输入颜色的**色相(Hue)**生成符合Material Design规范的完整主题,但黑色(#000000)属于无彩色,没有可提取的有效色相值。此时工具会触发默认回退机制,使用预设的色相值(对应深紫色#984061的色相)生成主题。

另外,你的代码中虽然手动定义了palettes.primary为黑色的色调板,但最终应用的是theme.schemes中的颜色(通过applyThemeVars读取colors.props),而这部分schemes是themeFromSourceColor生成的回退主题,所以实际生效的是深紫色而非黑色。

解决方法

要确保主色完全匹配指定的黑色,需要手动覆盖schemes中的主色相关属性,同时保持色调板与主题色阶的一致性。修改后的createTheme函数如下:

const createTheme = (): Theme => {
  const primaryArgb = argbFromHex(baseColors['primary']);
  const secondaryArgb = argbFromHex(baseColors['secondary']);
  const tertiaryArgb = argbFromHex(baseColors['tertiary']);
  const errorArgb = argbFromHex(baseColors['error']);
  const neutralArgb = argbFromHex(baseColors['neutral']);
  const neutralVariantArgb = argbFromHex(baseColors['neutralVariant']);

  // 生成黑色的色调板
  const primaryPalette = TonalPalette.fromInt(primaryArgb);
  // 先生成基础主题,再替换主色相关属性
  const theme = themeFromSourceColor(primaryArgb);

  // 覆盖浅色模式下的主色相关值
  theme.schemes.light.primary = primaryPalette.tone(40);
  theme.schemes.light.onPrimary = primaryPalette.tone(100);
  theme.schemes.light.primaryContainer = primaryPalette.tone(90);
  theme.schemes.light.onPrimaryContainer = primaryPalette.tone(10);

  // 覆盖深色模式下的主色相关值
  theme.schemes.dark.primary = primaryPalette.tone(80);
  theme.schemes.dark.onPrimary = primaryPalette.tone(20);
  theme.schemes.dark.primaryContainer = primaryPalette.tone(30);
  theme.schemes.dark.onPrimaryContainer = primaryPalette.tone(90);

  return {
    source: primaryArgb,
    schemes: theme.schemes,
    palettes: {
      primary: primaryPalette,
      secondary: TonalPalette.fromInt(secondaryArgb),
      tertiary: TonalPalette.fromInt(tertiaryArgb),
      neutral: TonalPalette.fromInt(neutralArgb),
      neutralVariant: TonalPalette.fromInt(neutralVariantArgb),
      error: TonalPalette.fromInt(errorArgb),
    },
    customColors: [],
  };
};

修改说明

  • 手动生成黑色的色调板primaryPalette,确保色调板的基础是指定的黑色
  • 覆盖theme.schemes.light和theme.schemes.dark中所有主色相关的属性,使用黑色色调板对应的标准色阶(符合Material Design的主题色阶规范)
  • 这样既保留了Material Design主题的完整色彩结构,又保证主色完全匹配你指定的黑色

内容的提问来源于stack exchange,提问作者AyAnniix

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 11:05:23