浏览器颜色格式指南:为什么整站换肤首选 OKLCH
CSS 能写颜色的方式很多,但真正适合「改一个值,整站风格跟着走」的并不多。本文先扫一遍浏览器支持的颜色格式,再重点讲 OKLCH 的优缺点,以及用 oklch + --hue 做整站主题色的实现方案(本站 blog 主题就是这套思路)。
浏览器支持的颜色格式一览
按成熟度与能力,大致可以分成三层。
1. 经典 sRGB(几乎无处不支持)
- 命名色:
red、transparent、currentColor - Hex:
#f00/#ff0000/#ff000080 - rgb() / rgba():现代写法可
rgb(255 0 0 / 50%) - hsl() / hsla():按色相/饱和度/明度调色,直觉强但感知不均
- hwb():Hue + Whiteness + Blackness,适合「掺白掺黑」
2. 感知均匀 / 广色域(2023 起主流可用)
oklch() / oklab():Chrome 111+、Firefox 113+、Safari 15.4+lab() / lch():CIE Lab/LCH,同代支持color():指定色域,如color(display-p3 1 0 0)color-mix():在指定色彩空间里混色(建议in oklch)
3. 相对颜色(Relative Color,稍晚成熟)
形如 oklch(from var(--brand) calc(l + 0.1) c h)。Chrome/Edge 131+、Firefox 133+、Safari 18+ 支持较完整。很适合从基色派生 hover/浅色,但整站主色仍更稳妥地用「CSS 变量 + oklch」显式声明。
OKLCH 是什么
OKLCH 是 OKLab 的圆柱坐标写法,三个通道职责清晰:
- L(Lightness):感知明度,约 0–1(也可用百分比)
- C(Chroma):彩度,大约 0–0.4 常见可用区间
- H(Hue):色相角度 0–360
1/* L C H [/ alpha] */2color: oklch(0.55 0.14 250);3color: oklch(0.55 0.14 250 / 80%);45/* 色相交给变量,是整站换肤的关键 */6--hue: 250;7--accent: oklch(0.5 0.15 var(--hue));
OKLCH 的优点
- 感知均匀:同样改 ΔL,不同色相看起来「变亮/变暗」更接近一致;HSL 的 L 做不到这点。
- 通道可拆:只动 H 换品牌色,只动 L 做暗色模式,只动 C 控制鲜艳度——整站主题系统非常吃这套模型。
- 可表达广色域:在支持 Display P3 的屏幕上,能比 hex/rgb 更鲜艳;超出 sRGB 时浏览器会合理映射。
- 与 color-mix / relative color 搭配好:混色、派生 hover、半透明叠层时,结果更「像人眼预期」。
- 浏览器支持已够用:到 2026 年,基础
oklch()对多数站点可直接作为默认,不必再当 progressive enhancement。
OKLCH 的缺点与坑
- 色域裁剪:高彩度 C 在某些色相会超出显示色域,浏览器会 gamut map,可能「看起来没那么艳」。设计时别盲目拉高 C。
- 与 HSL 色相不完全同轴:同样写 250,OKLCH 与 HSL 视觉色相会有偏差。从旧 HSL 主题迁移时,别假设数字可直接平移。
- 设计工具链路仍在补齐:Figma 等对 OKLCH 支持不如 hex 成熟,团队协作常要转换。
- 极旧浏览器会整条忽略:若仍要照顾很老的内核,需先写 sRGB fallback,再写 oklch。
- Canvas / 第三方库未必原生理解:WebGL、部分图表库仍要 RGB;需要在 JS 侧转换(可用 culori 等)。
整站风格修改:推荐实现方案
核心思路只有一句话:把色相抽成单一 token --hue,其余颜色用 oklch(L C var(--hue)) 或 calc(var(--hue) + 偏移) 派生。
步骤 1:定义色相 token 与语义色板
1html.blog-skin {2 --hue: 250;34 /* 背景:高 L、极低 C,仍带一点主题色气 */5 --page-bg: oklch(0.98 0.008 var(--hue));6 --card-bg: oklch(1 0.004 var(--hue));7 --card-border: oklch(0.92 0.02 var(--hue));89 /* 文字:中低 L,弱彩度,避免「发灰」或「发脏」 */10 --text: oklch(0.28 0.02 var(--hue));11 --text-muted: oklch(0.45 0.03 var(--hue));1213 /* 强调色:固定 L/C,只换 H */14 --accent: oklch(0.5 0.15 var(--hue));15 --accent-2: oklch(0.55 0.14 calc(var(--hue) + 30));16 --accent-3: oklch(0.55 0.14 calc(var(--hue) + 60));17}
组件里尽量只用语义变量(--accent、--text),不要散落硬编码 hex。这样改风格 = 改 token,而不是满仓库搜色值。
步骤 2:暗色模式只改 L(和少量 C)
1html.blog-skin.dark {2 --page-bg: oklch(0.14 0.015 var(--hue));3 --card-bg: oklch(0.18 0.02 var(--hue));4 --card-border: oklch(0.28 0.02 var(--hue));5 --text: oklch(0.95 0.01 var(--hue));6 --text-muted: oklch(0.7 0.02 var(--hue));7 /* 暗色下强调色略提亮、略降彩,避免刺眼 */8 --accent: oklch(0.72 0.12 var(--hue));9}
色相继续共用 --hue,亮暗切换不会把品牌色「拧歪」。
步骤 3:运行时改 --hue 即可换肤
1const DEFAULT_HUE = 2502const HUE_KEY = 'themeHue'34function applyHue(value) {5 const n = Math.max(0, Math.min(360, Math.round(Number(value))))6 document.documentElement.style.setProperty('--hue', String(n))7 localStorage.setItem(HUE_KEY, String(n))8}910// 页面加载恢复用户偏好11const saved = localStorage.getItem(HUE_KEY)12if (saved != null) applyHue(saved)1314// UI:滑块 / 色板只改这一个数15// applyHue(180) → 整站背景、边框、强调色、标签色一起偏移
本站 header 的「主题色」面板就是这样做的:写 --hue,CSS 里所有 oklch(... var(--hue)) 自动重算,无需重渲染组件树。
步骤 4:用色相偏移做「同族多彩」
标签、语法高亮、装饰渐变不需要第二套主题系统,只要在主色相上加固定偏移:
1.chroma-tag--0 { color: oklch(0.48 0.15 calc(var(--hue) + 0)); }2.chroma-tag--1 { color: oklch(0.48 0.15 calc(var(--hue) + 55)); }3.chroma-tag--2 { color: oklch(0.48 0.15 calc(var(--hue) + 110)); }45--prose-hr-gradient: linear-gradient(6 90deg,7 oklch(0.48 0.15 calc(var(--hue) + 0)),8 oklch(0.48 0.15 calc(var(--hue) + 110)),9 oklch(0.48 0.15 calc(var(--hue) + 220))10);
步骤 5:半透明与叠色用 color-mix(in oklch, …)
1--accent-soft: color-mix(in oklch, var(--accent) 22%, transparent);2--accent-shadow: color-mix(in oklch, var(--accent) 30%, transparent);34/* 需要透出底图时,再把不透明 base 混一点透明 */5--header-bg: color-mix(in oklch, var(--header-bg-base) 85%, transparent);
步骤 6:可选 fallback(仅当要照顾极旧浏览器)
1.button {2 background: #5b4fcf; /* sRGB fallback */3 background: oklch(0.5 0.15 270);4}56@supports (color: oklch(0 0 0)) {7 .button {8 background: oklch(0.5 0.15 var(--hue));9 }10}
为什么不优先用 HSL 做整站主题
HSL 也能 hsl(var(--hue) 70% 45%),写法更熟。问题在于:相同「明度百分比」在黄/蓝上视觉权重差很大——换肤时有的色相显得过亮刺眼,有的又发闷。OKLCH 的 L 更接近人眼,一套 L/C 表跨色相更稳,维护成本更低。
选型速查
- 整站主题 / 换肤:oklch + --hue(首选)
- 半透明、叠色、hover:color-mix(in oklch, …)
- 指定 P3 等色域:color(display-p3 …)
- 从已有色派生通道:relative color(注意浏览器版本)
- 对外素材 / 邮件 / 极旧兼容:hex / rgb 作 fallback
小结
浏览器颜色格式已经从「只能写 hex/rgb」走到「感知均匀 + 广色域 + 混色」的新常态。若目标是改整站风格,OKLCH 是目前最均衡的选择:L/C/H 可独立控制,配合单一 --hue 就能完成亮暗模式、强调色、多彩标签与运行时换肤。代价是需要习惯新数字空间,并留意高彩度裁剪与工具链转换——但对现代站点来说,这点成本通常值得。
想直观感受效果:打开本站 header 的主题色滑块,拖动色相,看背景、按钮、标签与代码高亮如何一起偏移。那就是 OKLCH 整站主题方案最有说服力的演示。
- test