关于 OKLCH
8/10/2025
传统 RGB 与 HSL 色彩空间:基础与局限
RGB 与 HSL 的基本原理
RGB 色彩模型是一种基于三原色光(红 Red, 绿 Green, 蓝 Blue)混合的加色模型,是屏幕等发光设备呈现色彩的基础。在 CSS 中,RGB 颜色常通过 rgb(r, g, b) 函数或十六进制代码(如 #RRGGBB)表示,其中 r, g, b 的值域通常为 0 至 255。尽管 RGB 对于计算机硬件而言高效且直接,但其表示方式对于人类的直观理解和色彩调整带来了挑战。设计者和开发者难以仅通过调整 R, G, B 的数值来精确预测颜色的亮度、饱和度或色调变化。更为关键的是,RGB 并非感知一致 (perceptually uniform)。这意味着,在色彩空间的不同区域,相同的 RGB 数值变化可能导致人眼感知到的颜色差异迥异。例如,在深色区域,RGB 的微小变动可能难以察觉,而在亮色区域,同样幅度的变动则可能非常显著。此外,传统的 RGB 通常局限于 sRGB 色域(这与早期CRT显示器等技术背景相关),无法完整展现现代宽色域显示器所能呈现的丰富色彩。
为弥补 RGB 在直观性上的不足,HSL (Hue, Saturation, Lightness - 色相, 饱和度, 亮度) 色彩空间应运而生。它试图以更符合人类描述颜色的习惯方式来组织颜色。HSL 可以视为 RGB 色彩空间的圆柱坐标变换:
- H (Hue - 色相): 表示颜色的基本属性,如红、黄、蓝等,通常以 0 到 360 度的角度值表示。
- S (Saturation - 饱和度): 表示颜色的纯度或鲜艳程度,通常以百分比 (0% - 100%) 表示,0% 为灰色,100% 为最纯的颜色。
- L (Lightness - 亮度): 表示颜色的明暗程度,通常以百分比 (0% - 100%) 表示,0% 为黑色,100% 为白色,50% 则被认为是该色相最饱和(纯粹)状态的亮度基准。

在 CSS 中,HSL 颜色通过 hsl(h, s, l) 函数表示。相较于 RGB,HSL 在某些场景下,如选取特定色相后调整其饱和度与亮度,确实提供了更高的直观性。然而,HSL 存在一个核心且突出的缺陷:其 “L” (Lightness) 分量的感知不一致性。尽管其名称包含“亮度”,但 HSL 的 L 值并不能准确反映人眼的感知亮度。其亮度L通常基于RGB分量进行简单数学计算,如 L = (max(R,G,B) + min(R,G,B)) / 2。这种计算方式并未充分考虑人眼对不同色光(例如,黄色固有高感知亮度,蓝色则偏低)的敏感度差异。因此,不同色相的颜色,即便具有完全相同的 HSL 亮度值 (L),其视觉上的明亮程度也可能存在巨大差异。一个经典的例证是,HSL 中的纯黄色 (如 hsl(60, 100%, 50%)) 在视觉上远比纯蓝色 (如 hsl(240, 100%, 50%)) 更为明亮,尽管它们的 L 值均为 50%。

这种感知上的不一致性给实际设计工作带来了诸多困扰。当设计者试图运用 HSL 的 L 值来统一不同颜色的视觉亮度,或基于 L 值生成颜色系列(如色阶或阴影)时,其结果往往与预期不符。例如,为蓝色按钮和黄色按钮设置相同的 L 值,它们在视觉重量上会显得失衡。同样,对不同色相的颜色应用相同的 L 值调整(如增加 10% 的 L 值)可能会产生感知亮度上截然不同的变化幅度。这使得创建一致的视觉层级、确保足够的颜色对比度以满足可访问性要求,以及生成平滑和谐的颜色派生变得尤为困难。
传统色彩空间的共同挑战
无论是 RGB、HSL 还是 HSV (Hue, Saturation, Value),它们在色彩调整和色板生成方面均面临着由感知不均匀性引发的挑战。设计者难以通过简单的数学运算或参数调整来生成视觉上和谐、亮度过渡平滑的色板。例如,在 HSL 中,若固定 L 和 S 值,仅改变 H 来生成一系列颜色,这些颜色在感知亮度上会出现明显的跳跃。更为严重的是,这种感知不均匀性对数字产品的可访问性构成了障碍。确保文本与背景之间、UI 元素之间具有足够的对比度,对于视觉障碍用户至关重要。然而,若色彩空间的亮度参数不能真实反映感知亮度,那么依赖这些参数来评估对比度的可靠性便无从谈起。
特别是 HSL 的 L 值,由于其与感知亮度的脱节,使得基于它来判断对比度往往会产生误导。HSL 的“直观性”在一定程度上是一种“虚假的便利”。它最初的出现确实是为了解决 RGB 不够直观的问题,引入了人类熟悉的色相、饱和度、亮度概念。设计者初接触 HSL 时,可能会认为其比 RGB 更易于理解和操作颜色。然而,这种“易用性”是以牺牲感知准确性为代价的。在对可访问性和视觉一致性要求日益提升的现代设计实践中,HSL 的这一根本性缺陷使其难以胜任。
感知一致颜色空间:更符合人类视觉的色彩模型
什么是感知一致颜色空间 (Perceptually Uniform Color Space)?简单来说它是一种特殊的颜色模型,其核心设计目标是使颜色之间的数值距离(例如,在空间中两点间的欧几里得距离)与人眼感知到的颜色差异尽可能成正比。在这样的色彩空间中,对颜色参数进行等量的调整,无论起始颜色为何,所引起的视觉变化感知应当是相似的。其核心原则在于模拟人类视觉系统处理颜色信息的方式,力求让色彩空间中的数学运算结果与真实的视觉感知变化保持一致。
感知一致性的重要性体现在多个方面:
- 可预测性 (Predictability): 当对颜色进行调整时,其视觉结果更加符合预期。
- 一致性 (Consistency): 在生成色板、创建颜色渐变时,能够帮助保持视觉上的和谐与平滑过渡。例如,在感知一致空间中对两个颜色进行插值生成的渐变,通常比在 sRGB 空间中(由于其非线性感知特性,直接线性插值RGB值)生成的渐变看起来更自然,能够有效避免 sRGB 渐变中常见的“灰色死区”或意外的色相偏移。
- 设计应用 (Design Applications): 设计者可以更容易地创建视觉平衡的调色板,并精确控制界面中的视觉层级。
- 可访问性 (Accessibility): 这是感知一致色彩空间最重要的优势之一。其亮度参数能更真实地反映人眼感知到的亮度,为评估和确保颜色对比度提供了可靠基础。例如,Stripe 公司在构建其可访问颜色系统时,便利用了 CIELAB 色彩空间的感知一致性,通过调整颜色的 L* 值来确保不同颜色组合达到一致的感知对比度,满足 WCAG 要求。
CIELAB (Lab) 和 LCh 是两种广为人知的感知一致色彩空间的代表,主要应用于印刷和工业颜色质量控制。CIELAB 由国际照明委员会 (CIE) 定义,包含 L* (感知亮度), a* (红/绿轴), b* (黄/蓝轴)三个分量。LCh 则是其圆柱坐标表示,包含 L* (感知亮度), C* (彩度), h (色相角)。
感知一致性并不仅仅是一项技术改进,它从根本上改变了设计者与颜色互动的方式。在传统色彩空间下,设计师往往需要依赖大量经验和反复视觉调校。而感知一致色彩空间(特别是其准确的亮度参数)使得基于数学规则和算法的色彩系统设计成为可能,这对于创建和维护现代复杂设计系统(支持多主题、明暗模式、严格无障碍标准)至关重要。
OKLCH:新一代色彩解决方案
什么是 OKLCH?
在对色彩表达与控制进行持续优化的进程中,OKLCH 色彩空间应运而生,它标志着向更精确模拟人类视觉感知迈出的重要一步。
Oklab 及其极坐标形式 OKLCH 是由 Björn Ottosson 于 2020 年提出的新型感知色彩空间。其创建的主要动机是为了解决现有色彩空间(包括被广泛应用的 CIELAB,其在某些色相区域,如蓝色区域,仍存在感知均匀性不足的问题)在感知一致性方面存在的不足。Ottosson 的目标是创建一个不仅感知上更均匀,而且在计算上更简单、表现更稳定的色彩空间,尤其适合Web及数字显示应用。具体技术细节可参阅其文章:https://bottosson.github.io/posts/oklab/
相较于 CIELAB/LCH,Oklab/OKLCH 在多个关键的感知维度上展现出更优的性能,尤其是在色相线性度和色相均匀性方面有显著改进。这意味着当你在 Oklab/OKLCH 中降低一个蓝色的彩度时,它会平滑地趋向灰色,而不太可能像在某些CIELAB区域那样意外地偏向紫色或绿色;同时,色轮上不同色相之间的感知差异也更为均衡,使得色彩选择和过渡更加自然和谐。

OKLCH 与 HSL 类似,也包含三个核心参数:
- L (Lightness - 感知亮度): 范围通常为 0 (黑) 到 1 (白)。至关重要的是,此处的“感知”意味着 L 值的变化与人眼实际感受到的明暗变化高度一致。
- C (Chroma - 彩度): 代表颜色的“鲜艳程度”。范围从 0 (灰色) 开始,数值越大颜色越鲜艳。对于sRGB色域,C值实用上限通常在0.37附近,而对于更广的Display P3色域,则可达到约0.5。CSS中
OKLCH()函数的C值若用百分比表示,0%对应0,100%对应0.4。 - H (Hue - 色相): 代表颜色的基本色调,0 到 360 度的角度值。
此外,通常还包含 Alpha (透明度) 分量。
为什么是 OKLCH?
OKLCH 之所以被认为是下一代色彩解决方案的有力竞争者,主要归功于其以下几个显著优势:
- 卓越的感知一致性: L (感知亮度) 分量确保数值变化与人眼感知高度吻合。W3C CSS Color Module Level 4 规范指出其在色相线性度、均匀性方面优于CIE LCH。
- 更直观、可预测的色彩调整与派生: 其L, C, H参数具有良好的正交性,即调整一个参数时,其他感知属性几乎不受影响。这非常适合生成色板。例如,设计师可以通过固定H和C,仅调整L来创建一组单色的亮度阶梯,用于组件的不同状态(如按钮的悬停、按下、禁用);或者固定L和C,改变H来获得一组感知亮度与彩度一致的多色系选择,非常适用于数据可视化中确保不同系列图表元素的视觉平衡。创建用户界面主题(如从浅色模式到深色模式的平滑且视觉一致的过渡)也因此变得更加系统和可控。
- 支持广色域 (Wide-Gamut Colors): OKLCH能轻松表示如Display P3等广色域的颜色,充分利用现代显示器的色彩能力。
- 提升可访问性 (Accessibility, a11y): 可靠的L值是确保视觉对比度、满足WCAG等标准的基础。
- 人类可读性:
OKLCH(0.7 0.15 200)比rgb(128, 177, 207)或#80B1CF更能直观传达颜色的大致外观(一个较亮的、中等偏低饱和度的蓝色)。
未来趋势与标准化进展
OKLCH 的诸多优势使其成为 CSS 色彩表示的理想候选者。它已被 W3C 的 CSS Color 规范所采纳,并已成为 Baseline 2023 newly available 的组成部分,标志着其在主流浏览器中的广泛可用性。
CSS 在 Color Module Level 4 中正式引入了 OKLCH() 和 oklab() 函数。CSS Color Module Level 5 进一步增强了 OKLCH 的实用性,例如其核心特性如相对颜色语法和color-mix()函数。
- 相对颜色语法 (Relative Color Syntax): 允许基于“源颜色”方便地创建和修改颜色,如
OKLCH(from var(--brand-blue) calc(l * 0.8) c h),对创建颜色状态和主题变体极为有用。
:root {
--color-btn: OKLCH(45% 0.3 266);
}
.btn {
padding: 12px;
background-color: var(--color-btn);
border: none;
cursor: pointer;
color: white;
}
.btn:hover {
background-color: OKLCH(from var(--color-btn) calc(l + 0.2) c h);
}
color-mix()函数: 允许在指定色彩空间中混合颜色。在OKLCH空间中混合颜色,例如color-mix(in OKLCH, blue, yellow),可以产生更符合视觉预期的中间色,有效避免了在sRGB中混合时常出现的颜色变“脏”、饱和度降低或意外色相偏移(如蓝色和黄色混合趋向灰色而非绿色)的问题,从而得到更鲜明、纯净的混合效果。
.container-1 {
background-color: color-mix(in OKLCH, yellow, blue);
width: 20rem;
height: 2rem;
}
.container-2 {
margin-top: 1rem;
background-color: color-mix(in srgb, yellow, blue);
width: 20rem;
height: 2rem;
}
目前,已有越来越多的项目和团队,例如 linear、stripe、tailwindcss,开始采用 OKLCH 来构建具有可访问性的、可预期的色彩系统, 并以此作为设计系统的基础。
OKLCH 目前所面临的问题
尽管 OKLCH 前景广阔,但在其推广和应用过程中仍有一些方面需要注意:
色域映射 (Gamut Mapping) 与溢色 (Out-of-Gamut) 处理
OKLCH 可以定义出超出特定显示设备色域的颜色。当这些“溢出”颜色需要在较窄色域(如sRGB)显示时,必须进行“色域映射”。CSS Color Module Level 4 规范推荐在 OKLCH 空间中执行色域映射。这样做的好处在于,当需要将广色域颜色压缩至目标显示设备(如sRGB)的较小色域时,OKLCH能够更好地保持原始色彩的感知特征,如相对亮度和色相关系,从而避免简单裁剪(clipping)方法常导致的色调突变或细节丢失,生成视觉上更自然的降采样颜色。然而,不同浏览器和工具的具体映射算法和效果可能仍有细微差异,需要实际测试。
浏览器适配问题
在OKLCH的早期推广和浏览器实现阶段,曾出现过一些兼容性和渲染准确性的问题,例如特定L值(L=1或L=0时C不为0)的颜色未按预期显示为纯白或纯黑,以及一些特定的渲染错误。随着浏览器厂商对规范的持续跟进和修复,这些早期较为显著的兼容性问题在当前(2025年5月)主流浏览器版本中已基本得到解决。然而,在处理极端颜色值或进行复杂色域转换时,我们仍需关注并测试其在不同环境下的表现。

设计工具原生支持的普及程度
尽管 OKLCH 在 Web 标准层面已趋成熟,设计工具生态的跟进仍是一个持续发展的过程。早期,主流图形设计工具的原生支持有限,构成了一定的推广瓶颈。虽然主流设计工具可以通过一些 trick 和插件支持 OKLCH 色彩空间。例如 Figma 可以通过在偏好中修改为 P3 色域来支持显示 OKLCH 颜色(修改后需要在新建文件中才能支持)。即便如此,与传统色彩模型的无缝集成度相比,仍有不少提升空间。

OKLCH in Action
好了!在充分理解OKLCH的理论基础之后,本节我们将通过 huetone 工具,一步步展示如何构建一个包含品牌色、警告色、成功色和危险色(即语义色)的色板。这个过程能帮助你直观感受OKLCH在创建和谐、可预测色彩系统时的效能。除了 huetone,下面还列出了一些利用 OKLCH/Oklab 或类似感知一致原理进行色板生成和颜色调整的代表性工具:
- https://huetone.ardov.me/
- https://uicolors.app/
- https://OKLCH.com
- https://harmonizer-web.web.app/
- https://github.com/dokozero/okcolor
- https://m3.material.io/blog/material-theme-builder
在开始之前:激进 or 稳定?
在项目初期,关于如何应用OKLCH,通常有两种策略考量:
- 直接采用策略:在生产环境中直接使用 CSS 的
oklch()函数,充分利用其全部特性。例如,最新的 Tailwind CSS 4.0 便采用了此策略。这种方式能最大化 OKLCH 的优势,但需关注对极少数不支持 CSS Color Level 4 的旧版本浏览器的兼容性处理(截至2025年,主流浏览器均已提供稳定支持)。 - 转换输出策略:在色板构建阶段利用 OKLCH 的感知一致性优势进行色彩定义,随后将选定的颜色转换为广泛兼容的 RGB 或十六进制 (HEX) 值应用于生产环境。此方法类似于 Babel 将较新版本的 JavaScript 转换为向后兼容代码,旨在平衡先进性与广泛的兼容性。然而,采用此策略时需特别注意,从 OKLCH 这样宽广的色域向 sRGB 这类相对较窄的色域转换时,高饱和度颜色可能会出现视觉上的变化或细节损失。
这次的演示将遵循后一种思路,重点展示如何利用OKLCH进行色板构建,并探讨其输出为传统格式的过程。
步骤一:品牌色色板
品牌色通常在视觉识别 (VI) 系统设计阶段即已确定。即便如此,仍建议负责设计系统的设计师能早期介入此过程,与平面设计师协作,以确保品牌色从源头便具备良好的数字产品适应性、可访问性与扩展潜力。本例中,我们选用一个常见的蓝色 #0052d9 作为演示起点。
选定基础色后,需确定色阶的数量。通常,10至12个色阶(例如,从最亮到最暗分为11阶)能够满足多数场景的需求,而中性灰色系可能需要更多阶数以实现更细腻的过渡。
在命名规范上,可借鉴如 Tailwind CSS 等成熟的设计系统方案,采用 50, 100, 200, ..., 500, ..., 900, 950 这样的数字序列。相较于简单的 1-9 序列,这种方式为后续在现有色阶间插入新的颜色(例如在 800 和 900 之间补充 850)提供了结构上的便利,增强了系统的可扩展性。注意在这里我们不会讨论 design token primitive 和 semantic 命名相关的知识。
品牌主色(Base Color)一般位于色板的中间区域(例如 500 或 600 色阶),并以此为基准向两侧(更亮和更暗)延伸,以适应浅色及深色模式的色彩需求。当然,主色的具体位置并非固定不变,应根据其固有的 Lightness、Chroma 和 Hue 特性灵活调整。
在这些都确定后,我们打开 huetone,删除掉 example 的其他颜色,保留一行,增加两列命名为 900 和 950。将 500 应用为我们的品牌色 #0052d9。

然后选择 apply hue to the row,整行都会使用相同的 Hue 值,然后我们需要慢慢调整亮度的分布,也可以直接使用线性或者是 cubic 函数来进行快速采样。
在实际操作中,可能会遇到这样的情况:选定的初始品牌色,其本身(例如相对于白色背景)的APCA 对比度已经非常高。此时若仍将其置于中间的500色阶,可能难以生成足够数量且符合对比度要求的、视觉上区分明显的更暗色阶。例如,若 #0052d9 与白色的APCA对比度已达80,将其置于 800 色阶可能会是更合理的选择,使其作为色板中较深且能代表品牌特性的颜色。此番调整意味着主色不再居中。若目标是创建一套能同时良好服务于亮暗两种模式的色板,则可能需要在可用色阶范围或主色定位上进行权衡;或者,也可以考虑为亮色和深色模式分别维护独立的色板体系(例如,深色模式下的色阶顺序可以与浅色模式相反),参考 radix UI 的方法。
将品牌色移到800后,我们就需要调整亮度与饱和度的值。对于 Chroma,我一般采取 base color 最高,向两侧削微递减的形式,这样可以让 base color 的饱和度最高,其余颜色可以担任辅助性角色。

步骤二:应用到其他颜色
当主色板的L和C分布模式(可视为定义好的亮度曲线和彩度曲线)调整满意后,可以利用Huetone的“复制上一行 (Copy Last Row)”功能,快速创建其他颜色(如成功色Success、警告色Warn、错误色Error)的初始色板。此复制操作将完整继承上一行所有色阶的L和C值。
新行复制完成后,首要任务是调整其主色阶(例如,与品牌色主色阶对应的800阶)的色相(H)值,以定义新的语义色(例如,选择一个绿色调的H值代表成功色)。在调整H的同时,往往需要同步微调其彩度(C),一方面确保该颜色在目标输出色域(如sRGB)内,避免溢出,另一方面也需顾及视觉上的和谐与信息的有效传递。OKLCH的感知一致性在此处再次体现其优势:在改变H时,设计者能较好地预估L和C的视觉效果,并有助于维持感知亮度的相对稳定。
新的色相和彩度确定后,再次使用“将当前色相应用于整行 (Apply current hue to row)”功能,即可快速生成该语义色的完整色阶。其他语义色板(如警告色、错误色)的创建过程与此类似。

Excellent!现在我们已经有一个色板的雏形了!
值得强调的是,尽管已有不少工具和算法能够基于单一输入色自动生成色板,且 OKLCH 本身在感知一致性方面表现出色,但要达到理想的色彩设计效果,设计师的视觉判断和细致的手动调校往往是不可或缺的。工具是高效的助手,而非最终审美的替代者。
步骤三:迭代、测试与导出
初步色板生成后,迭代与优化是确保其最终可用性的关键环节。这包括在实际用户界面中严格测试各种颜色的可访问性(例如,使用 APCA 或 WCAG 标准检查文本与背景的对比度)、评估其在不同组合及光照环境下的视觉效果,以及确保整体色板的和谐统一。
此阶段通常需要设计、产品、研发等团队成员间的紧密沟通与协作,收集并整合各方反馈,确保色彩系统既能满足具体业务需求,又能在技术上稳妥实现。持续的沟通与精细的调整是打造成功色彩系统的必经之路。
当所有颜色及其阶数最终确定后,便可将其导出为CSS自定义属性(变量)、JSON数据、或特定设计工具所需的格式,以便在项目中统一应用。
/* Example Palette copy color palette */
/* brand */
--brand-50: #e9eff9;
--brand-100: #e0eafb;
--brand-200: #c9daf8;
--brand-300: #acc8f9;
--brand-400: #8bb3f9;
--brand-500: #6fa0f8;
--brand-600: #4d86f0;
--brand-700: #3271e7;
--brand-800: #0052d9;
--brand-900: #0c41a2;
--brand-950: #0d2e6c;
/* success */
--success-50: #e9f1e8;
--success-100: #e0eede;
--success-200: #c9e1c6;
--success-300: #b2d1ad;
--success-400: #96c090;
--success-500: #7fb079;
--success-600: #639b5b;
--success-700: #488b3f;
--success-800: #24741a;
--success-900: #1b5913;
--success-950: #123d0d;
/* warn */
--warn-50: #f6ede4;
--warn-100: #f5e7d8;
--warn-200: #eed4ba;
--warn-300: #e9be93;
--warn-400: #e0a567;
--warn-500: #d78f3d;
--warn-600: #be781f;
--warn-700: #a6691f;
--warn-800: #88530a;
--warn-900: #674012;
--warn-950: #472c0c;
/* error */
--error-50: #f8ebe8;
--error-100: #fae4df;
--error-200: #f6cfc7;
--error-300: #f4b6a9;
--error-400: #e99c8d;
--error-500: #e28471;
--error-600: #d36450;
--error-700: #c74934;
--error-800: #ae270f;
--error-900: #871c0a;
--error-950: #601004;
相关阅读
- 色彩空间与色域知识梳理及设计应用
- Stripe: Accessible color systems
- Matthew Strom: Generating Color Palettes
- Evil Martians: OKLCH in CSS: why we moved from RGB and HSL
- Björn Ottosson: A perceptual color space for image processing (Oklab)
综上所述,OKLCH 色彩空间凭借其卓越的感知一致性、对广色域的良好支持以及在提升数字产品可访问性方面的巨大潜力,正成为现代色彩设计与开发领域的一项重要革新。它不仅为设计师和开发者提供了更科学、更直观的色彩工具,也为创造出视觉更和谐、体验更一致、对所有用户更友好的数字产品开辟了新的道路。虽然在工具链的完美整合和极端情况下的色域处理方面仍有持续优化的空间,但 OKLCH 无疑代表了 Web 色彩光明的未来。