寻求基于参考色生成互补色、色调的React/CSS Modules计算公式
动态生成互补色与色调:告别手动维护颜色集合
兄弟,我太懂你手动写一堆颜色对象的痛苦了——不仅工作量大,遇到新的参考色还要手动找互补色,完全没法灵活适配所有场景。其实咱们可以利用颜色模型的数学公式,从单一Hex/RGB参考色动态生成互补色、色调变体,彻底解放双手!
核心思路:用HSL模型处理颜色
互补色在色轮上是相差180度的颜色,而HSL(色相Hue、饱和度Saturation、亮度Lightness)模型的色相值是0-360度的数值,调整起来比Hex或RGB直观太多。所以核心步骤是:
- 将Hex/RGB转换为HSL
- 调整色相值生成互补色(H±180°),或调整饱和度/亮度生成色调变体
- 转换回Hex/RGB供React和CSS Modules使用
一、必备的颜色转换工具函数
先写几个通用的转换函数,这些都是标准的颜色模型转换公式,直接用就行:
1. Hex转RGB
处理3位(如#fff)和6位(如#ffffff)Hex格式:
function hexToRgb(hex) { // 统一转换为6位Hex const normalizedHex = hex.length === 4 ? `#${hex[1]}${hex[1]}${hex[2]}${hex[2]}${hex[3]}${hex[3]}` : hex; const r = parseInt(normalizedHex.slice(1, 3), 16); const g = parseInt(normalizedHex.slice(3, 5), 16); const b = parseInt(normalizedHex.slice(5, 7), 16); return [r, g, b]; }
2. RGB转HSL
把RGB值转为HSL的色相、饱和度、亮度:
function rgbToHsl(r, g, b) { r /= 255; g /= 255; b /= 255; const max = Math.max(r, g, b); const min = Math.min(r, g, b); let h, s, l = (max + min) / 2; if (max === min) { h = s = 0; // 灰度色,无色相和饱和度 } else { const d = max - min; s = l > 0.5 ? d / (2 - max - min) : d / (max + min); switch (max) { case r: h = (g - b) / d + (g < b ? 6 : 0); break; case g: h = (b - r) / d + 2; break; case b: h = (r - g) / d + 4; break; } h /= 6; } return { h: h * 360, // 转为0-360度的色相值 s: s * 100, // 转为0-100%的饱和度 l: l * 100 // 转为0-100%的亮度 }; }
3. HSL转RGB
调整后的HSL值转回RGB:
function hslToRgb(h, s, l) { h /= 360; s /= 100; l /= 100; let r, g, b; if (s === 0) { r = g = b = l; // 灰度色 } else { const hue2rgb = (p, q, t) => { if (t < 0) t += 1; if (t > 1) t -= 1; if (t < 1/6) return p + (q - p) * 6 * t; if (t < 1/2) return q; if (t < 2/3) return p + (q - p) * (2/3 - t) * 6; return p; }; const q = l < 0.5 ? l * (1 + s) : l + s - l * s; const p = 2 * l - q; r = hue2rgb(p, q, h + 1/3); g = hue2rgb(p, q, h); b = hue2rgb(p, q, h - 1/3); } return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)]; }
4. RGB转Hex
把RGB值转回Hex格式:
function rgbToHex(r, g, b) { const componentToHex = (c) => { const hex = c.toString(16); return hex.length === 1 ? `0${hex}` : hex; }; return `#${componentToHex(r)}${componentToHex(g)}${componentToHex(b)}`; }
二、生成互补色的函数
把上面的工具函数组合起来,一行代码生成互补色:
function getComplementaryColor(hex) { const [r, g, b] = hexToRgb(hex); const { h, s, l } = rgbToHsl(r, g, b); // 互补色相:原色相加180度,超过360则取模 const complementaryHue = (h + 180) % 360; const [newR, newG, newB] = hslToRgb(complementaryHue, s, l); return rgbToHex(newR, newG, newB); }
测试示例:输入#c80eff(紫色),会生成#00ff31(黄绿色)——标准的互补色!
三、扩展:生成自定义色调变体
如果需要不同亮度/饱和度的颜色(比如你示例里的#fab81e、#00ff9c这类变体),可以写一个通用函数:
// 生成指定亮度(0-100)和饱和度(0-100)的颜色变体 function generateColorVariant(hex, lightness = 50, saturation = 100) { const [r, g, b] = hexToRgb(hex); const { h } = rgbToHsl(r, g, b); const [newR, newG, newB] = hslToRgb(h, saturation, lightness); return rgbToHex(newR, newG, newB); }
比如:
- 生成更亮的互补色:
generateColorVariant(complementaryColor, 70) - 生成低饱和度的参考色:
generateColorVariant(baseColor, 50, 50)
四、在React + CSS Modules中落地
最优雅的方式是用CSS变量,把动态计算的颜色注入到全局或组件级变量中,CSS Modules直接引用即可:
1. React组件代码
import { useEffect } from 'react'; import styles from './App.module.css'; // 把上面的所有工具函数放在这里,或者单独抽成utils文件 function hexToRgb(hex) { /* ... */ } function rgbToHsl(r, g, b) { /* ... */ } function hslToRgb(h, s, l) { /* ... */ } function rgbToHex(r, g, b) { /* ... */ } function getComplementaryColor(hex) { /* ... */ } function generateColorVariant(hex, lightness, saturation) { /* ... */ } function App({ baseColor = '#c80eff' }) { const complementaryColor = getComplementaryColor(baseColor); // 生成底部组件的浅色调互补色 const bottomWidgetColor = generateColorVariant(complementaryColor, 75); // 生成右侧组件的低饱和度参考色变体 const rightWidgetColor = generateColorVariant(baseColor, 60, 70); useEffect(() => { // 将颜色设置为根元素的CSS变量,全局可用 document.documentElement.style.setProperty('--toolbar-color', baseColor); document.documentElement.style.setProperty('--center-widget-color', complementaryColor); document.documentElement.style.setProperty('--bottom-widget-color', bottomWidgetColor); document.documentElement.style.setProperty('--right-widget-color', rightWidgetColor); }, [baseColor]); return ( <div className={styles.app}> <div className={styles.toolbar}>Toolbar</div> <div className={styles.centerWidget}>Center Widget</div> <div className={styles.bottomWidget}>Bottom Widget</div> <div className={styles.rightWidget}>Right Widget</div> </div> ); } export default App;
2. CSS Modules代码(App.module.css)
.app { min-height: 100vh; display: grid; grid-template-areas: "toolbar toolbar toolbar toolbar" "center center center right" "bottom bottom bottom bottom"; gap: 1rem; padding: 1rem; } .toolbar { grid-area: toolbar; background-color: var(--toolbar-color); color: white; padding: 1rem; border-radius: 4px; } .centerWidget { grid-area: center; background-color: var(--center-widget-color); padding: 2rem; border-radius: 4px; } .bottomWidget { grid-area: bottom; background-color: var(--bottom-widget-color); padding: 1rem; border-radius: 4px; } .rightWidget { grid-area: right; background-color: var(--right-widget-color); padding: 2rem; border-radius: 4px; }
现在,只要改变baseColor,所有组件的颜色都会自动更新,完全不用手动维护颜色集合了!
内容的提问来源于stack exchange,提问作者toto
相关产品推荐
相关产品推荐

