原文链接:
当设计一个新组件库时,搭建色彩系统往往是第一件事。作者通过项目经验结合理论知识,带来这篇 YUX 最硬核的色彩系统设计文章


前言


当我们开启一个新组件库的设计时,搭建色彩系统往往是我们要做的第一件事。色彩系统的设计是很有趣的事,总有一种常做常新的奇妙新鲜感,随着设计理念的演进、相关设计工具的出现,每隔一段时间笔者去探索实践色彩系统设计时,总能发现一些新玩意,并将其引入到设计流程中,实践更高效科学的构建方式。本文将结合笔者在最近的通用组件库中的实践,以及在海外项目不同产品的色彩系统的迭代,来分享一些笔者对色彩系统设计的经验,欢迎大家交流和探讨。

定义优秀的色彩系统


在开始介绍如何设计色彩系统前,笔者想先简单定义一下什么是优秀的色彩系统,明确这些标准可以为我们后续搭建过程中的设计决策提供清晰可靠的判断依据。

image.png

易生产


想必没有设计师希望设计一套色彩系统要用上七七四十九天,走完整个设计流程仿佛经历了九九八十一难一般。虽然对于一个产品的设计系统来说,搭建色彩系统往往是一次性投入,后续只需要维护即可,所以搭建成本好像并不重要。但生产成本其实是对色彩系统内部复杂度的反映,高生产成本的色彩系统必然充满混沌,而这与「系统」概念本身背道而驰;与之相对,生产成本和复杂度更低的系统通常更有序,也具备更强的一致性,而且往往能通过程序或工具实现自动化生产。


易维护


随着需求迭代,产品升级,色彩系统也需要随之动态调整,最常见的就是增加新的颜色。若色彩系统设计之初,缺乏深思熟虑,将系统的拓展性、兼容性一并考虑上,后续的维护会变的无比艰难,甚至演变成一场严重的灾难!色彩系统的可维护性是让其保持活力的重要保障,也是系统健壮性和可靠性的最好的体现。

易上手


色彩系统最终要给到项目中的其他设计师一起使用,只有准确、符合直觉的语义别名、精简的颜色类型才能有效帮助设计师快速上手整个色彩系统,在产品界面的设计过程中准确使用每一个颜色。除了设计师友好之外,当色彩系统通过 Design Tokens 连接设计与开发时,开发人员也成了色彩系统的用户,因此色彩系统应为所有人而设计,即使没有专业背景也可以学习和理解。


符合无障碍设计


随着无障碍设计受到从业者越来越多的关注,颜色作为产品的视觉无障碍的重要部分,色彩系统中相关语义别名的颜色之间对比度需匹配 WCAG 对比度标准,以保证界面上视觉元素的可辨识度。
以上便是笔者认为的优秀的色彩系统应具备的特征,易生产、易维护、易上手、符合无障碍设计。有趣的是优秀的色彩系统往往会给人一种简洁、秩序的美感。


创建色彩系统

ps: 本文不会涉及前期的品牌色定义,色系选择、搭配等流程,我们将聚焦色彩系统中最重要的生产与落地环节,分析现状与问题,引入无障碍标准和新工具,构建科学的色彩系统。

色彩系统通常会包含两部分,一是 color palette(基础色板),由主色、辅色、中性色等颜色生成的梯度色组成,是产品内所有可能使用颜色的最大集合,整个色彩系统的底层基础;二是 color scheme(配色方案),从基础色板中选取合适的颜色,根据该颜色在产品界面中实际使用的场景对其命名,也就是为颜色创建 semantic alias(语义化别名),配色方案是整个色彩系统的核心,也是我们日常设计工作中实际使用的部分。
image.png
▲ 通过一个 key color 生成 palette,将 palette 中的颜色使用语义重新命名,明确其应用范围构成我们在设计工作中使用的 scheme。
基础色板与配色方案的组合应该是适用面最广的最佳实践,但色彩系统的结构不是死板的,需要根据实际需求出发进行调整和取舍,像精简、敏捷的个人项目只需要配色方案即可,但如果面向灵活、庞大的组件系统,可能除了基础色板与配色方案之外,还需要在往上架设一层 component-specific color scheme(组件配色方案)实现更多定制的能力。

创建基础色板


创建基础色板的方式和工具有很多,最常见的应该是基于 HSV/HSL 色彩空间,为 H、S、V 三个参数分别设定数值范围与插值曲线,从而生成一组梯度色的方法,大部分一键生成色板的工具均基于此原理,如 ColorBox 就是其中非常有代表性也非常实用的色板生成工具,想必很多设计师也都使用过。但是,这个使用范围最广,接受度最高设计方法本身存在一个致命的问题,那便是使用了错误的色彩空间。
image.png
▲ ColorBox 是基于 Lyft 团队的开源算法上线的 Web 工具,其原理是为颜色的 hue、saturation、value 分别设定数值范围(Rang)和插值曲线(Curve),相当于创造了一条在 H S V 三维空间内的连续曲线,而最后输出的色板就是设定的梯度序列在曲线上的取色的集合。


HSV/HSL 色彩空间的局限

为什么说我们常用的创建色板的设计方法使用了错误的色彩空间?首先要从 HSV/HSL 色彩空间在表达色彩亮度时存在的问题说起。作为设计师应该都会有类似的经验,相同 saturation(饱和度) 和 value(亮度)的色彩,在不同的 hue (色相)上的亮度感知是完全不一样的,其原因是 HSV/HSL 色彩空间是应用于数字化图像处理领域,为了方便机器理解、计算、呈现而设计,是人类视觉的线性模型,但人类的感知却是非线性的,所以造成数值与感知不匹配的问题。
image.png
▲ 相同 saturation(饱和度) 和 value(亮度)数值,在不同的 hue(色相)上视觉感知的亮度完全不同,其实际的亮度与其下方对应的灰阶更为接近。
其次要理解色彩系统中色彩亮度的意味着什么?我们后续在设计配色方案时,需保证相关语义别名的颜色之间对比度符合 WCAG 标准,如内容与背景的颜色之间对比度需到 4.5 以上而,而对比度的本质是两个颜色之间感知亮度的差异。毫无夸张的说,色彩系统的本质是围绕亮度组合的设计,但是颜色的数值本身不提供任何与感知亮度相关的信息,我们也无法直接从两个颜色的数值上判断出他们的亮度差异(即对比度)。
image.png
▲ 如果不借助对比度检测工具,我们很难从梯度色中为次级文本选取符合无障碍标准的颜色
最后,基于上述问题,我们可以还原一下设计师在搭建色彩系统时的真实情景与坎坷遭遇。因为HSV/HSL 颜色数值与人类的视觉感知亮度不匹配,导致我们如果使用相同参数生成的色板在不同色相上整体呈现的亮度差异很大,为了相对和谐的色彩搭配效果,那么必须要设计师的额外介入,耗费时间和精力手动调整参数,而且这个过程全凭设计师的主观判断,主观判断便意味着非标准化。 即便设计师调教了一组相对和谐的基础色板,为了使配色方案中颜色的搭配符合 WCAG 对比度标准,还需要设计师对用到的颜色反复做对比度检查。 很快设计师就会陷入来回修改,不断拉扯的境地,特别是对于一些非常纠结的设计师来说简直是一场令人身心俱疲的噩梦。


全新的 HCT 色彩空间

既然 HSV/HSL 色彩空间的颜色亮度数值与视觉感知无法匹配,那么是否存在以人类视觉感知角度开发的色彩空间?答案当然是肯定的,早在 1976 年国际照明委员会就定义了 CIELAB (L_a_b*)色彩空间,旨在提供一个与人类感知统一的空间,除此之外,还有还有一系列基于 CIELAB 演化而来的色彩空间,如 LCH、OkLab、HCT 等。在这些色彩空间中,笔者非常推荐 HCT,这也是目前笔者在项目实践中使用的方案。
image.png
▲ Lab、LCH、OkLab、HCT 色值,其中标重的数值为亮度,其颜色的亮度与实际感知统一
HCT 是 Google 为了更好的色彩呈现,以及更方便的通过程序自动生成色彩,而发明的「全新」色彩空间,H 即 hue 色相,C 即 chroma 色度,可以理解为色彩浓度,T 即 tone 光度,也就是亮度 。
image.png
▲ HCT 由 hue、chroma、tone 构成,hue 与 chroma 来自 CIMA16,tone 来自 Lab 的 L| 图片来自 Designing Harmony into Dynamic Color

如果读者查阅过 Material Design 3 的色彩规范部分,那么对 HCT 应该不会陌生,作为和新规范一起推出的色彩空间,HCT 是 Android 12 上 Dynamic Color (动态主题)背后的关键技术之一。

那么我们如何使用 HCT 色彩空间生成色板?Google 在上线新规范的同时也上线了 Material Theme Builder 工具,只需输入一个颜色便可以一步到位,自动生成包含基础色板与配色方案的色彩系统,还可以直接导出相关代码。Material Theme Builder 有网页版与 Figma 插件版,使用非常方便。
image.png
▲ Material Theme Builder | 图片来自 Figma community

但 Material Theme Builder 无法完成除定义颜色以外的任何调整,比如说增减或自定义色板梯度,没办法 🤷‍♀️ Material Theme Builder 设计之初也不是用来生成基础色板的。不过 Google 在其上线后没多久,也将其色彩空间的算法开源,我们可以直接调用 Material color utilities 库的方法,创建基于 HCT 色彩空间的基础色板。

生成基础色板的代码也非常简单,将颜色和亮度分别通过 TonalPalette 的 fromInt() 和 tone() 方法传入,即可返回该颜色在特定 tone下对应的颜色,如果我们给到一组亮度序列即可生成对应梯度的色板。
使用上述的方法,能很方便的生成我们想要的基础色板,除此之外我们还能再做一点点🤏优化,比如加入官方的 Harmonization 功能, 根据我们设定的目标颜色,自动微调其他颜色的 hue 和 chroma 让颜色在视觉上更加和谐。另外考虑到后续的生产流程,顺便生成我们需要的数据对象,直接复制粘贴会方便些。
借助 Material color utilities 库提供的方法生成的基础色板,不同颜色在同一个 tone 梯度上拥有完全一致的亮度表现。
image.png
▲ 利用 Material color utilities 生成的基础色板。

For the first time, designers have a color system that truly reflects what users see, taking into account a range of variables to ensure appropriate color contrast, accessibility standards, and consistent lightness/colorfulness across hues.

如 Google 的色彩科学家 James O’Leary 在 The Science of Color & Design 所说,这是设计师第一次拥有真正能与用户的视觉感知相匹配的色彩系统。


将基础色板导入 Figma

通过代码生成基础色板后,我们还需要将其添加到组件库中,因为笔者所在的项目目前使用 Figma Tokens 插件来管理设计系统的 Design Tokens(设计变量),所以在上面的代码中还顺便生成了 Figma tokens 可用的数据对象,我们将其复制到插件中即可完成导入,另外 Figma Tokens 插件可以在 Figma 中一键创建 styles,省去了我们一个个手动创建的繁琐过程。后续我们也只需要借助 Figma Tokens 插件管理、同步、导出色彩系统即可。
image.png
▲ Figma tokens 是一款功能强大且真正意义上的 token 管理工具


对创建基础色板部分做个简单总结


聊到这里,创建基础色板的部分也告一个段落了。笔者之前接手过几个不同的项目,负责其组件系统的设计,以往每每设计到色彩系统时都会感到非常难受,UI 和 UX 设计应该是一个基于变量、条件和逻辑的系统过程,这是业界的共识,但唯独在色彩系统的设计上,长久以来是一个纯主观的「行为艺术」,让 10 个设计师来设计色彩系统,可以设计出 10 个完全不重样的,而且他们会觉得自己设计的是最好的🙃。

颜色的选择与搭配上缺少可量化的客观标准是造成上述问题的主要原因,不过随着符合无障碍的对比度标准正在成为大家在设计中必须考虑到的点,围绕这条标准让设计师设计颜色变得更加理性,再加上像 HCT 这类与感官一致色彩空间与相关算法的开源,我们得以借助程序自动生成色彩系统,没有了设计师这个主观因素的参杂,让色彩系统的设计变得简单纯粹高效。


创建配色方案

在创建完色板之后,我们将从色板中挑选在 UI 界面中实际会使用到的颜色,依照用途对其重新命名,这个过程就是所谓的语义化,这些带语义化别名的颜色会重新构成一组直接用于产品界面的色板,即配色方案 color scheme。符合直觉,表意明确的配色方案可以帮助设计师在使用颜色时消除困惑与分歧,保证设计的一致性。
image.png
▲ 设计师使用颜色时只需要根据 UI 元素选取对应的语义的颜色即可。
配色方案的设计是一个繁琐的决策过程,虽然在👆上文我们用一句话「依照用途对其重新命名」概述了整个过程,但实际操作起来还是有很多细节值得深思熟虑和推敲,毕竟命名这种事在各种场合下都挺困难。
image.png
▲ 不仅是色彩系统的命名,整个设计系统的命名都让人头秃 | 图片来自 @joeyabanks


基于语义模版(Patterns)为颜色命名

对颜色的语义化本质是对 UI 界面的解构,界面元素的关系、类型、状态都相对固定,因此我们可以基于特定结构的语义模版(Patterns)去命名,可以帮助设计师系统性的构建逻辑统一、表达明确的命名体系。但受限于本文篇幅和主题问题,笔者就不对语义模版展开讲解了,推荐大家阅读 Nathan Curtis 的 Naming Tokens in Design Systems,这篇文章系统的介绍了语义模版的结构体系,文中将其分为四个部分:

1.命名空间,即适用范围,包含 system、theme、domain

2.对象,即 UI 元素实体,包含 group、component、element

3.基础样式,包含 category、concept、property

4.修饰,包含 variant、state、scale、mode
image.png
▲ 语义模版构成类型
语义模版适用于设计系统内颜色、尺寸、间距、字体等所有 Design Tokens 的命名,针对颜色来说,我们只需要选取其中部分节点,拼装成适合我们应用场景的语义模版即可,比如笔者在当前项目中使用的是一套借鉴了 Material Design 3 和 Asanas Design System 后设计的语义模版: theme-variant—property-mode-scale-state ,那么命名一个报错情景下的主文本用色就是 light-negative-content(后面几项为默认值因此省略)。
image.png
▲ 基于语义模版帮助设计师快速构建逻辑统一、表达直观的命名体系。
不过,基于语义模版的命名还是有两个需要注意的点:

① 语义精度需要合理把控,不同精度的语义适用于不同的场景。

如果我们在语义模版中加入像 element 或 component 节点,会收窄语义的应用范围,即精度更高,粒度更细。举个🌰例子,以 component-property-variant 模版命名按钮背景色 button-bg-primary,那么该颜色仅能应用在 button 的 primary 样式的 default 状态上,非常明确,毫无歧义,但是如高精度的语义从系统一致性的角度看,意味着我们需要为所有 UI 元素都单独命名!这会导致语义别名数量爆表,非常臃肿,生产成本也随着上升。

之前提到的「component-specific color scheme」就属于这类高精度的语义,其在组件系统里应用还是比较多的。
image.png
▲ Ant design 的组件样式表 | ant-design
反之,结构更简单、粒度更大、表意更笼统的语义模版则不会严格限制颜色的使用场景,如 primary-light ,这是描述相对更浅的主色别名,我们可以在任意需要浅色主色的背景或者文本上使用。非常自由,但代价是会增加设计师对颜色使用的判断成本,特别是存在两个颜色区分度不够的情况下。额外的判断也意味着出错和混乱,另外其后续维护和拓展的难度也会更高。
image.png
▲ 图上的四种组合哪种才是正确的?

因此我们需要根据产品特性选择合适的语义精度,设计适合项目的语义模版。

② 语义层级需要命名统一,数量可控。

在实际设计过程中,不少 UI 元素在视觉呈现上会有不同层级的需求,所以在语义模版中,层级(scale)节点必不可少。比如文本的颜色一般会有深色、浅色等,我们可以将其命名为 text-default text-medium text-weak ,这里我们使用了 default / medium / weak 之类表强度的词语来表示层级,那么从一致性的角度考虑,其他 UI 元素的层级用词应相同,如果此时我们需要给背景命名,则背景的命名应是 bg-default bg-medium bg-strong 等。

不像状态(state)或变体(variant)对其描述的用语相对固定,可用于表示层级的词语却非常多,比如:

1.数字,如 1,2,3,4 或 50, 100,200,300

2.尺寸,如 small,medium,large

3.强度,如 weak,medium,strong

4.高度,如 low, medium,high

5.刻度,其与元素本身的属性相关,如基础色板中颜色使用的是颜色自身的 tone 值

实际使用中,笔者会推荐使用 2、3、4 类层级数量可控,无法随意增加的用词,这里可能会有读者产生疑问,为什么要使用这类灵活性低、拓展性弱的层级用词?其实这是一种自我约束,因为层级与具体场景关联性较弱,我们应该避免在系统中创建过多的层级,更多的层级选项便意味着语义不明确,徒增理解和判断成本。换个角度说如果某一个 UI 元素需要 4 个以上层级,那要么是 UI 设计太「奔放」,需要收敛些;要么是语义本身出了问题,最常见的就是把层级与其他节点混合到了一起。
image.png
▲ 单一语义节点下层级数量不要超过 3 个,减少不必要的理解和判断成本。

另外值得一提是,避免使用 primary、secondary、tertiary 表示层级,因为这些词可能会在产品主色或组件 props 的命名上使用,为了避免歧义与冲突,命名应独立不重复。

最后,我们如何判断配色方案的语义系统是合适的?非常简单,将设计的配色方案给合作的设计师和开发看下,如果对方不借助你为每个语义写的备注与描述,只看语义别名就可以对每个颜色的使用场景理解的七七八八,说明这套配色方案设计的不错,易于上手。反之,则说明还有优化的空间,主要是检查下命名是否符合直觉,以及站在全局的角度看,命名是否出现冲突等。


符合无障碍标准配色方案


除了语义化命名外,在设计配色方案的过程中,还需要考虑内容与背景的对比度应满足无障碍标准,即对比度至少大于 4.5,HCT 色彩空间除了解决视觉感知统一的问题,而且可以直接测量对比度:

1.只要任意两个颜色 tone 的数值差大于等于 40 时,其两者之间的对比度必然大于等于 3

2.只要任意两个颜色 tone 的数值差大于等于 50 时,其两者之间的对比度必然大于等于 4.5

3.只要任意两个颜色 tone 的数值差大于等于 70 时,其两者之间的对比度必然大于等于 7
image.png
▲根据颜色之间 tone 的差值就可以判断颜色之间的对比度
这也是设计师第一次有能力不借助对比度检测器,直接判断任意两个颜色之间的对比度是否达到无障碍要求。假设我们的背景色使用的是 tone 为 90 的颜色,那么内容颜色的 tone 至少为 40。有这种特性存在,我们从基础色板为语义选择合适的颜色轻松简单直观了许多。

另外还有三个值得注意的点:

1.颜色的设计顺序建议从背景开始,按层级向上设计,因为对比关系都是发生在背景与内容之间,确定背景后,我们根据对比度标准就可以快速确定其上方内容颜色。

2.在同一个背景上,无论颜色的表意倾向如何,同一层级颜色的 tone 应相同。其中的逻辑也很简单,层级高低本质是颜色之间对比度大小,若层级相同,那么对比度也相同,在同一个背景上对比度相同的颜色,必然其 tone 也相同。举个🌰例子,相同层级的表达错误与成功的内容颜色 negative-content 与 positive-content 的 tone 相同。
image.png
▲ 同一层级颜色的 tone 应相同

3.无障碍除了我们常说的对比度标准以外,在设计过程中,可能还需要考虑对色觉识别障碍,即「色盲」群体的适用性,我们可以直接使用像 Color Blind 插件自动模拟不同类型色盲下看到的颜色效果,并做相应的优化。
image.png
▲ Color Blind | 图片来自 Figma community


将 Color scheme 导入 Figma

与前文创建基础色板的过程类似,我们同样使用 Figma tokens 插件创建和管理配色方案,需要注意的是,因为配色方案使用的颜色均来自基础色板,所以我们应在 value 输入引用的颜色名,将颜色的映射关系保留,而不是直接写死色值,可以让后续的调整更加灵活,也符合 Single source of truth 理念。
image.png
▲ 在Figma tokens 中保留颜色引用关系

我们在 Figma 中生成 style 后,如果需要展示用的页面或者文档,可以直接使用 color style guide 插件自动生成。


色彩系统创建之后…

至此,色彩系统的基础色板和配色方案就算搭建完成了,我们也在 Figma 中快速创建了对应的 style,那么这套色彩系统已经可以投入日常工作中直接使用了。

但是感觉是不是哪里缺了些什么?没错,你的感觉完全正确,创建完色彩系统其实只是开始,后续的 dark mode 设计、更新维护、布道、对接开发都是非常重要的部分,但受限于篇幅与本文的主题,这就不展开细聊了,简单分享下笔者的几点想法:

1.如何设计 dark mode ?

配色方案的颜色均是取自基础色板, dark mode 也不例外。大部分情况下,我们只需要将 light 颜色的 tone 在基础色板上取对位即可,需要注意的两点:一是这种做法会导致背景颜色之间的层级关系出错,需要手动调整下;二是如果你的用户大部分时候是在暗光环境中使用 dark mode,那么可以考虑适当增加相关颜色 tone 的差值以提高颜色之间的对比度,因为光强降低会导致人的Contrast sensitivity(对比敏感度)降低。其实暗光环境下颜色设计还是有不少需要注意的点。

2.如何更新与维护?

在文中笔者提到使用 Figma tokens 插件对色彩系统进行管理,因此后续所有的更新与维护均是基于该插件进行操作,修改之后只需要点击 update 就可以自动修改 Figma 中对应命名的 style。不过这个插件还是有一定的上手难度,推荐大家先看下 官方文档 与插件作者在油管上的 介绍视频

3.如何对接开发?

Figma tokens 插件可以将其导出为 json 交付开发。如果你的动手能力比较强,可以考虑使用插件的同步功能,将 json 放到像 GitHub 或 GitLab 的代码仓库中,那么每次修改后让开发去仓库里自取就好。另外我们还可以借助像 Github 的 workflow 实现一些自动化流程,比如调用 style dictionary 根据 json 自动生成各端代码;使用 Webhook 在每次更新后自动推送到工作 IM 之类…

4.如何布道?

当我们为流程和设计方法做了一点创新,如何让团队的其他同事理解和接受?那也只能是多做分享了,所以大家才会看到这篇文章🤣

5.还有什么其他要补充的么?

当然。

首先,有没有替代 HCT 实现基础色板感知亮度一致的工具?答案是有,Adobe 的 Leonardo,一款基于对比度生成颜色的超强工具,在 Material color utilities 开源前,笔者使用其作为替代第一次生成了统一亮度的基础色板。另外这个工具的设计师专门写了好几篇非常棒的文章布道他的理念,这些在 Leonardo 官网的 Articles 标签页中可以看到。
image.png
▲ Leonardo
其次, 有没有办法生成带 alpha,同时感知亮度一致的基础色板 ?答案是可以,使用 Alphredo,可以将我们导入的颜色自动生成带 alpha 但是看起来完全一致的颜色,具体的介绍可以看开发者的 介绍视频
image.png
▲ Alphredo
虽然这个工具也有 Figma 插件,但无法接入程序自动生成的流程,所以笔者去研究查找了一番,参考 Stack Overflow 上的回答写了个方法实现了同样的效果,经过测试和 Alphredo 基本一致。
// convert hex to rgb
const hexToRgb = (hex) => {
let color = hex.replace(/^\s#|\s$/g, “”);
if (color.length === 3) {
color = color.replace(/(.)/g, “$1$1”);
}
return {
r: parseInt(color.slice(0, 2), 16),
g: parseInt(color.slice(2, 4), 16),
b: parseInt(color.slice(4, 6), 16),
};
};

// convert opaque color to transparent version on arbitrary background color
const transparentColor = (forground, background = “#ffffff”) => {
const forgroundRgb = hexToRgb(forground);
const backgroundRgb = hexToRgb(background);

if (!forgroundRgb || !backgroundRgb) {
return null;
}
const { r: fr, g: fg, b: fb } = forgroundRgb;
const { r: br, g: bg, b: bb } = backgroundRgb;

let rgba = {
r: -1,
g: -1,
b: -1,
a: 0,
};

while (
rgba.a < 1 &&
(rgba.r < 0 ||
rgba.g < 0 ||
rgba.b < 0 ||
rgba.r > 255 ||
rgba.g > 255 ||
rgba.b > 255)
) {
rgba.a = rgba.a + 1 / 256;
const inv = 1 / rgba.a;
rgba.r = fr inv + br (1 - inv);
rgba.g = fg inv + bg (1 - inv);
rgba.b = fb inv + bb (1 - inv);
}

rgba.r = Math.round(rgba.r);
rgba.g = Math.round(rgba.g);
rgba.b = Math.round(rgba.b);
rgba.a = Math.round(rgba.a * 100) / 100;

return rgba(${rgba.r}, ${rgba.g}, ${rgba.b}, ${rgba.a});
};

最后,如果你看到了这里,也对色彩产生了更多探索研究的兴趣,那就对了!色彩本身是以光学为基础,涉及生物学、心理学、美学与艺术理论的复杂科学,真的有非常多可以学习的知识等你去发现和挖掘,笔者强烈安利去 Color and Contrast 上学习色彩的相关理论。

A comprehensive guide for exploring and learning about the theory, science, and perception of color and contrast.

正如该网站介绍的,这是一个探索和学习颜色理论的综合指南,相信可以为你打开新世界的大门!
References
1. Understanding Success Criterion 1.4.6: Contrast (Enhanced) : https://www.w3.org/WAI/WCAG21/Understanding/contrast-enhanced.html
2. ColorBox : https://colorbox.io/
3. CIELAB色彩空间 : https://en.wikipedia.org/wiki/CIELAB_color_space
4. Designing Harmony into Dynamic Color : https://material.io/blog/dynamic-color-harmony
5. Material Design 3 : https://m3.material.io/
6. Introducing Material Theme Builder : https://material.io/blog/material-theme-builder
7. Material color utilities : https://github.com/material-foundation/material-color-utilities
8. The Science of Color & Design : https://material.io/blog/science-of-color-design
9. Figma Tokens : https://www.figma.com/community/plugin/843461159747178978/Figma-Tokens
10. Figma Tokens plugin doc : https://docs.figmatokens.com/
11. How to create Design Tokens in Figma with Figma Tokens : https://www.youtube.com/watch?v=zkLfw6Jb6WM
12. Naming Tokens in Design Systems : https://medium.com/eightshapes-llc/naming-tokens-in-design-systems-9e86c7444676
13. Color Blind : https://www.figma.com/community/plugin/733343906244951586/Color-Blind
14. Single source of truth : https://en.wikipedia.org/wiki/Single_source_of_truth
15. Color style guide : https://www.figma.com/community/plugin/941680506965181089/Color-Styleguide
16. Leonardo : https://leonardocolor.io/#
17. Alphredo : https://alphredo.app/
18. How can transparent palettes change your UI designs : https://www.youtube.com/watch?v=bUjXVtJ7bsM
19. Finding “equivalent” color with opacity : https://stackoverflow.com/questions/12228548/finding-equivalent-color-with-opacity
20. Color and Contrast : https://colorandcontrast.com/#/