应使用hsl变量拆解主色,定义--hue-primary、--sat-primary、--lum-primary-base三个基础变量,再通过calc()动态生成语义化色阶(如--color-primary-50/500/700),确保主题切换时色调连贯、亮度可控,且所有状态、伪类、svg、渐变均统一引用变量,并在暗色模式下仅调整明度以保持色相稳定。

用 HSL 变量拆解主色,避免硬编码十六进制
直接定义 --primary-color: #4a90e2 看似简单,但换主题时所有衍生色(hover、disabled、border)都要手动调色,极易失衡。真正可控的方式是把主色拆成 --hue-primary、--sat-primary、--lum-primary-base 三个变量,全部用无单位数值或带 % 的合法值(如 --sat-primary: 65% ✅,不是 "65%" ❌)。
这样后续所有变体都靠 calc() 动态生成,比如:
button {
background: hsl(var(--hue-primary), var(--sat-primary), var(--lum-primary-base));
}
button:hover {
background: hsl(var(--hue-primary), var(--sat-primary), calc(var(--lum-primary-base) - 10%));
}
button:disabled {
background: hsl(var(--hue-primary), calc(var(--sat-primary) * 0.3), calc(var(--lum-primary-base) + 15%));
}
好处是:改一个 --hue-primary,整套按钮、卡片、标签的色调自动偏移,视觉连贯不跳变。
按明度梯度生成色阶,命名体现语义与强度
别用 --color-blue-100 这类抽象名,初级项目更需要明确用途。推荐三层结构:
-
--color-primary-50:最浅,用于背景层或悬浮蒙层 -
--color-primary-500:标准主色,按钮默认态、链接色 -
--color-primary-700:较深,用于悬停、强调文字、边框
实现上统一基于基础 HSL 值推导:
:root {
--hue-primary: 210;
--sat-primary: 85%;
--lum-primary-base: 55%;
--color-primary-50: hsl(var(--hue-primary), var(--sat-primary), calc(var(--lum-primary-base) + 35%));
--color-primary-500: hsl(var(--hue-primary), var(--sat-primary), var(--lum-primary-base));
--color-primary-700: hsl(var(--hue-primary), var(--sat-primary), calc(var(--lum-primary-base) - 15%));
}
注意:Safari 旧版本对 hsl(var(), var(), var()) 解析不稳定,确保每个变量值本身不含引号,且单位写法统一(65% 而非 65 %)。
渐变与边框色也必须走变量链,不能漏掉伪类和 SVG
渐变不能整个塞进一个变量里(如 --gradient: linear-gradient(...)),那样就失去动态性。正确做法是抽离关键色停点:
- 定义
--color-gradient-start和--color-gradient-end - 在使用处拼接:
background: linear-gradient(135deg, var(--color-gradient-start), var(--color-gradient-end)) - SVG 的
fill、stroke,伪元素::before的background,全都得用var()引用,否则切换主题时会卡在旧色上
常见翻车点:给 button 写了 var(--primary-color),但忘了 button:focus 或 button:active 里还写着 #357abd —— 这种硬编码会直接破坏主题一致性。
暗色模式切换只调亮度,保持色相与饱和度稳定
系统级暗色适配优先用 @media (prefers-color-scheme: dark),但它必须作用于 :root,不能嵌套在组件里:
@media (prefers-color-scheme: dark) {
:root {
--lum-primary-base: 40%;
--color-text: #f0f0f0;
--color-bg: #121212;
}
}
关键逻辑是:只改 --lum-primary-base,--hue-primary 和 --sat-primary 保持不变。这样主色不会从“蓝”突然变成“紫”,用户感知到的是“变暗”,而不是“变色”。如果项目还需手动切换(非系统偏好),就用 html[data-theme="dark"] :root 替代媒体查询,并确保 JS 修改时用 document.documentElement.setAttribute('data-theme', 'dark'),而非直接操作 style.setProperty 覆盖整段 CSS。
最容易被忽略的是对比度验证——光把背景变黑、文字变白还不够,按钮 hover 后的亮度差是否仍 ≥ 4.5:1?这得靠工具实测,不能凭感觉。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











