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
相关产品推荐
相关产品推荐

