颜色函数这么多,为啥hwb()没人用,到底咋选?

2,772字
12–18 分钟
in

看到CSS颜色函数的使用统计图,hwb()那条线简直惨不忍睹。明明号称比hsl()更直观,结果大家都不买账,这背后到底有啥门道?今天就掰扯掰扯这个冷门颜色函数,顺便聊聊现在到底该用啥来调色。

目录

啥是hwb

hwb()全称Hue-Whiteness-Blackness,属于sRGB色域家族的成员。跟老熟人hsl()一样,第一个参数管色相(0到360度),但后面俩参数变成了加白(0%-100%)和加黑(0%-100%)。举个例子,想搞个浅橙色,hsl写法是hsl(30deg 100% 75%),而hwb写法是hwb(30deg 50% 0%)。看着是不是有点像拿白色颜料往纯色里兑?这种思维方式确实更贴近物理混色——调油漆时就是往基础色里加白加黑。

hsl与hwb掰手腕

直观性谁更强

拿调一杯奶茶色来比划。用hsl的话,得同时考虑饱和度和亮度两个维度;而hwb只需要想“我要往橙色里加50%白”,大脑瞬间就能反应过来。这玩意儿确实符合直觉——人类天生会想象“掺了多少白、掺了多少黑”。但问题来了,想调高饱和度的颜色咋整?hwb没有单独调饱和度的参数,加白加黑都会降低饱和度。比如想要个鲜艳的大红,hwb(0deg 0% 0%)就是纯红,但只要想调亮一点,加白就变成粉红,没法像hsl那样hsl(0deg 100% 50%)保持高饱和只调亮度。实际干活时,很多场景需要独立控制饱和度和明度,hsl反而更顺手。

实战调色对比

假设做一个按钮的悬停效果,从浅蓝变到深蓝。hsl方案:

.button {
  background: hsl(210deg 80% 60%);
}
.button:hover {
  background: hsl(210deg 80% 40%);
}

hwb方案:

.button {
  background: hwb(210deg 20% 0%);
}
.button:hover {
  background: hwb(210deg 0% 40%);
}

注意看,hwb里加黑40%得到深色,但原本的白色成分归零。这里有个隐藏坑:白值和黑值加起来不能超过100%,否则浏览器会强制钳位。比如写hwb(210deg 60% 60%)总和120%,实际渲染时按比例压缩,导致出来的颜色跟预期完全两码事。新手很容易栽在这上面,hsl就没这种幺蛾子。

新式颜色函数更香

lab与lch碾压老前辈

hsl和hwb都困在sRGB小圈子里,能显示的颜色有限。而lab()、lch()、oklab()、oklch()这些新函数能访问广色域,像Display P3里那些艳得发紫的绿、炸裂的红,老函数根本搞不出来。更牛的是感知均匀——在hsl里调亮度,中间调区域变化明显,暗部和亮部变化迟钝;而oklch调整亮度时,人眼感觉是平滑过度的。比如做一个渐变色,oklch(50% 0.2 240)oklch(70% 0.2 240),过渡均匀得一批,没有那种“突然跳一下”的断层感。

迁移到新函数的骚操作

方案一:从hsl平稳切换到oklch

先确定现有hsl颜色的色相、饱和度、亮度值。比如一个品牌主色hsl(240deg 70% 50%)。在支持oklch的浏览器里,可以直接用工具转换。手动估算的话,oklch的色相同样用角度,但彩度(第二个参数)范围0~0.4左右,亮度(百分比)范围0%~100%。拿这个蓝色为例,近似写成oklch(50% 0.2 240)。写个回退方案保平安:

.element {
  background: hsl(240deg 70% 50%);
  background: oklch(50% 0.2 240);
}

老浏览器用hsl,新浏览器用oklch覆盖。日常开发中,建议直接上oklch,因为2025年的现在,主流浏览器早就全支持了。

方案二:用lch制作动态配色系统

做一套组件库颜色体系,需要主色、浅色、深色变体。用lch能轻松搞定:固定色相和彩度,只调亮度。比如主色lch(60% 0.15 250),浅色版亮度调高到75%,深色版亮度压到35%。代码示意:

:root {
  --primary: lch(60% 0.15 250);
  --primary-light: lch(75% 0.15 250);
  --primary-dark: lch(35% 0.15 250);
}

这样整套配色天生和谐,不会出现浅色版色相偏移的尴尬。而用hwb搞同样的事,加白得到浅色往往色相会变灰,加黑得到深色又容易脏兮兮。

具体操作流程:抛弃hwb投奔oklch

假设项目里有一段老代码用了hwb,想换成更现代的写法。一步步来:

  1. 检查浏览器支持情况
    打开caniuse网站搜“oklch”,会发现2021年后所有现代浏览器都支持。不用再写回退,除非要兼容IE这种古董。
  2. 把hwb值转成oklch
    肉眼比对法:写两个色块并排,一个hwb(30deg 30% 0%),另一个用oklch(70% 0.15 30),在浏览器里微调oklch的亮度和彩度直到视觉一致。更精准的做法是用设计软件的颜色拾取器,或者在线转换工具(搜“hwb to oklch converter”)。例如浅橙色hwb(30deg 50% 0%)转换后约等于oklch(80% 0.12 30)
  3. 替换代码并验证
    把CSS里的hwb函数整行换成oklch。跑一下视觉回归测试,或者人工点一遍页面,确认颜色没跑偏。
  4. 享受广色域红利
    之后想用更鲜艳的颜色,比如苹果官方的那个亮橙色,hwb根本够不着。用oklch直接写oklch(75% 0.22 45),色彩炸裂又自然。

啥时候还值得用hwb

说实话,除非团队里有设计老炮习惯了“加白加黑”的调色逻辑,并且项目只用在sRGB显示器上,否则真没必要死磕hwb。但有一种场景——做颜色混合动画,比如从纯红渐变到纯白,hwb写法hwb(0deg 0% 0%)hwb(0deg 100% 0%),过渡中间态就是各种粉红色,逻辑清晰易懂。而hsl做同样动画要同时改饱和度和亮度,容易产生意外的灰调。

举个例子,做一个加载进度条,颜色从蓝逐渐变白:

@keyframes fadeToWhite {
  from {
    background: hwb(210deg 0% 0%);
  }
  to {
    background: hwb(210deg 100% 0%);
  }
}

这段动画中间不会出现脏兮兮的灰蓝色,每一步都是干净的天蓝到白。如果追求这种“无杂色”的明度变化,hwb确实有独到之处。

最后说句大实话,前端圈现在用hsl的占大头,因为普及早、文档多、顺手。而hwb出生晚(2021年才被浏览器支持),又赶上lab/lch/oklab/oklch这波新势力崛起,直接被前后夹击。与其纠结“为啥hwb没人用”,不如直接拥抱oklch这套未来十年的配色方案。码农们日常写样式时,闭着眼上oklch就完事了,色域广、感知均匀、代码还短,不香吗?至于hwb,就当个冷知识,偶尔玩票可以,生产环境真没必要宠它。