应只定义一个基础色--color-primary-base,其余语义色通过hsl(from var(--color-primary-base) h s calc(l±n))动态生成,确保主题切换时自动更新且维护可控。

直接用 hsl() 从一个基础色算出整套语义色,而不是手动定义一堆十六进制值。
用 hsl(from ...) 提取并调整基础色的 HSL 分量
现代 CSS 允许你把任意颜色(包括变量)拆成色相(h)、饱和度(s)、亮度(l),再做数学运算。这是派生颜色的核心能力。
-
--color-primary-base: #2563eb是唯一需要人工维护的基础色,其他全靠它生成 -
--color-primary-500: hsl(from var(--color-primary-base) h s l)等价于原色,是“中性基准” -
--color-primary-600: hsl(from var(--color-primary-base) h s calc(l - 15))暗一点,适合悬停背景 -
--color-primary-400: hsl(from var(--color-primary-base) h s calc(l + 10))亮一点,适合浅色文字或边框 - 别写
hsl(210 70% 45%)这种固定值——它和基础色脱钩,改主色时得同步改所有地方
避免在 :root 里硬写具体色值
很多人把 --color-primary-500: #2563eb 直接写死在 :root,结果换主题时只能全局搜索替换,极易漏改或误改。
- 正确做法:只在
:root定义空壳变量,比如--color-primary-base: #2563eb - 所有衍生色都放在
[data-theme="light"]或[data-theme="dark"]作用域里计算 - 这样深色模式只需重写
--color-primary-base,其余自动更新,无需额外维护 - 如果用了
color-mix(),注意 Safari 16.4+ 才支持;hsl(from ...)兼容性更好(Chrome 111+、Safari 16.2+、Firefox 110+)
组件内禁止声明新变量,只读不写
组件样式里出现 --btn-bg-hover 这类名字,说明 Token 体系已经失控——它本该由 --color-primary-600 和状态逻辑组合得出。
立即学习“前端免费学习笔记(深入)”;
- 按钮悬停背景色应写成:
background-color: var(--color-primary-600, #1d4ed8) - 文本禁用态颜色应写成:
color: var(--color-text-disabled, #6b7280),回退值必须是静态色,不能嵌套var() - 如果某个组件需要局部微调(比如卡片标题用更浅的蓝),就在
.card元素上重写--color-primary-400,而不是新建--card-title-color - 所有命名必须带语义前缀,如
--color-primary-500,而非--primary或--c1——后者无法定位用途,也无法批量替换
真正难的不是怎么算颜色,而是守住“只定义一个基础色”的纪律。一旦允许在任意层级塞进第二个基础色,整套推导就变成不可控的手动维护。


















