图解CSS: CSS 颜色

发布于 大漠

颜色的魅力是无穷的,它可以让本身很平淡的东西瞬间变得漂亮、美丽起来。正如古话所言,佛靠金装,人靠衣装一样,网页也是如此,随着互联网的迅速发展,只有简单的文字和图片的网页,无法满足人们的需求了,一个网页给人们留下的第一印象,既不是他的内容,也不是他的设计,而是整站的整体颜色,这将决定用户是否继续浏览下去。

为了能够达到人们的需求,Web设计师除了需要掌握网站制作的技术之外,还必须能够很好的应用Web颜色。换句话说,网站颜色的使用好坏,直接影响网站的生存力。

在Web世界中,给Web元素添加色彩主要是通过CSS来完成(抛开最早的开发模式)。在CSS中有一些属性允许开发来改变页面元素,比如边框色、阴影色、背景等;在CSS中还有很多颜色颜色值(单位)给属性设置颜色。说起CSS颜色,早期它是CSS 2.1规范中的一部分,但是由于CSS规范后期按功能模块化来划分之后,现在CSS的颜色存在于不同的规范中,比如颜色模块Level3Level4Level5

网页中的色彩特性

色彩的应用并不是想象的那么容易,在Web网页上,显示器中看到的色彩会随着显示器环境的变化而变化。特别是在Web页面这个特殊环境之下,色彩的使用就显得更加的困难,但是必须做到能够自由地使用色彩制作出漂亮的Web页面。这样一来,首先需要理解Web下的特殊环境,在了解色彩原理的基础上逐步掌握Web颜色的使用方法,才能制作出令人满意的Web页面。

网页色彩的表现原理

色彩在Web页面中会随着用户的显示器环境的变化而变化,所以无论多么相同的颜色,看起来都会有细微的差异。但这不是说关于色彩的基本概念不同,只不过是在Web页面中使用色彩需要让人更加费神伤脑筋。

早期在Web页面运用中,我们知道有256种Web安全颜色一说,其实这256种颜色是指8位颜色的表现能力,随着科技的发展,现在颜色不在局限于8位,16位色彩的发色总数是65536色,也就是216次方,而新增了24位元色彩,也就是224次方,即16777216种颜色。但32位色就并非是232次方的发色数,它其实也是16777216种颜色,不过它增加了256阶颜色的灰度。

至于32位色和16位色肉眼分辨不出来吗?其实如果用两台品牌型号都一样的显示器,分别调不同的颜色,就能看出区别,但是只是一台显示器的反复转换就很难分辨得出来。换句话说,现实世界中有无数种颜色,每一个物体都有它们自己的颜色。我们要做的工作是使用(有限的)数字来模拟真实世界中(无限)的颜色,因此并不是所有的现实世界中的颜色都可以用数字来表示。然而我们依然可以用数字来代表许多种颜色,并且你甚至可能根本感觉不到他们与真实颜色之间的差异。颜色可以数字化的由红色(Red)、绿色(Green)和蓝色(Blue)三个分量组成,它们通常被缩写为RGB

在现实生活中看到的某一物体的颜色并不是这个物体的真实颜色,而是它所反射的颜色。换句话说,那么被物体吸收的颜色(被反射的颜色)就是我们能够感知到的特体的颜色。例如,太阳光被认为是由许多不同的颜色组合成的白色光。如果我们将白光照在一个蓝色的物体上,这个蓝色折物体会吸收白光中除蓝色以外的所有颜色,不被吸收的蓝色光被反射到我们的眼中,使我们看到一个蓝色的物体。正如下图所示,是一个珊瑚红,它以不同强度的方式反射了几种不同的颜色:

正如你所见,白色的阳光是一种所有可见颜色集合,上面的物体吸收了其中的大部分颜色,它仅反射了那些代表这个物体颜色的部分,这些被反射颜色组合就是我们感知到的颜色(正如上图中的珊瑚红)。

而在屏幕显示器是由一个个1 x 1的被称为像素的点构成,利用电子束来表现色彩。像素把光的三原色:红色(R)、绿色(G)、蓝色(B)组合成的色彩按照科学的原理表现出来。一个像素包含8位元色彩的信息量,有从0~255256个单元,其中0是完全无光状态,255是最亮状态。

Web 页面的安全色

不同的平台(Mac、PC等)有不同的调色板,不同的浏览器也有自己的调色板。这就意味着对于一幅图,显示在Mac上的Web浏览器中的图像,与它在PC上相同浏览器中显示的效果可能差别很大。选择特定的颜色时,浏览器会尽量使用其本身所用的调色板中最接近的颜色。如果浏览器中没有所选的颜色,就会通过抖动或者混合自身的颜色来尝试重新产生该颜色。

为了解决Web调色板的问题,人们一致通过了一组在所有浏览器中都类似的Web安全颜色。这些颜色使用了一种颜色模型,在该模型中,可以用相应的16制进制值00336699CCFF来表达三原色(RGB)中的每一种。这种基本的Web调色板将作为所有的Web浏览器和平台的标准,它包括了这些16进制值的组合结果。这就意味着,我们潜在的输出结果包括6种红色调、6种绿色调、6种蓝色调。6 x 6 x 6的结果就给出了216种特定的颜色,这些颜色就可以安全的应用于所有的Web中,而不需要担心颜色在不同应用程序之间的变化。

对于我们来说,将某种颜色的10进制值转化为16进制值不是一件容易的事情,尽管我们可以学会将RGB颜色转化为16进制的数学原理。

但是我们使用大多数图像编辑或者绘画程序中提供的颜色转化工具进行转化更为容易。通过使用滴管工具,可以在任何所需的颜色上单击,然后再颜色的拾取器中查看该颜色的RGB、HSB、CMYK、LAB和最终16进制数值。

在CSS中表达颜色有多种方式。比如,用颜色名称表示,如blue表示蓝色;或用16进制的数值表示RGB的颜色值。RGB是Red,Green,Blue意思,RGB每个原色的最小值是0,最大值是255,如果换算成16进制表示,就是(#00),(#FF)。比如白色的rgb(255,255,255),就用#FFFFFF表示;还有黑色的rgb(0,0,0),就用#000000表示。

256色里有40种颜色在Macintosh和Windows里显示的效果不一样,所以能安全使用的只有216色。为了尽量让用户看到色彩相同的网页,请尽量使用下面的216色。

颜色值 颜色效果 颜色值 颜色效果 颜色值 颜色效果 颜色值 颜色效果 颜色值 颜色效果 颜色值 颜色效果
#000 #030 #060 #090 #0c0 #0f0
#003 #033 #063 #093 #0c3 #0f3
#006 #036 #066 #096 #0c6 #0f6
#009 #039 #069 #099 #0c9 #0f9
#00c #03c #06c #09c #0cc #0fc
#00f #03f #06f #09f #0cf #0ff
#300 #330 #360 #390 #3c0 #3f0
#303 #333 #363 #393 #3c3 #3f3
#306 #336 #366 #396 #3c6 #3f6
#309 #339 #369 #399 #3c9 #3f9
#30c #33c #36c #39c #3cc #3fc
#30f #33f #36f #39f #3cf #3ff
#600 #630 #660 #690 #6c0 #6f0
#603 #633 #663 #693 #6c3 #6f3
#606 #636 #666 #696 #6c6 #6f6
#609 #639 #669 #699 #6c9 #6f9
#60c #63c #66c #69c #6cc #6fc
#60f #63f #66f #69f #6cf #6ff
#900 #930 #960 #990 #9c0 #9f0
#903 #933 #963 #993 #9c3 #9f3
#906 #936 #966 #996 #9c6 #9f6
#909 #939 #969 #999 #9c9 #9f9
#90c #93c #96c #99c #9cc #9fc
#90f #93f #96f #99f #9cf #9ff
#c00 #c30 #c60 #c90 #cc0 #cf0
#c03 #c33 #c63 #c93 #cc3 #cf3
#c06 #c36 #c66 #c96 #cc6 #cf6
#c09 #c39 #c69 #c99 #cc9 #cf9
#c0c #c3c #c6c #c9c #ccc #cfc
#c0f #c3f #c6f #c9f #ccf #cff
#f00 #f30 #f60 #f90 #fc0 #ff0
#f03 #f33 #f63 #f93 #fc3 #ff3
#f06 #f36 #f66 #f96 #fc6 #ff6
#f09 #f39 #f69 #f99 #fc9 #ff9
#f0c #f3c #f6c #f9c #fcc #ffc
#f0f #f3f #f6f #f9f #fcf #fff

CSS中的颜色

色彩是很复杂的一门学科,真正的要聊的话,整本书都难说清楚。在这里,我们还是回到CSS的世界中来,接着聊聊CSS世界中的颜色。

在CSS的世界中,颜色可以分为两个部分:能运用颜色的CSS属性和运用于CSS属性的颜色值。CSS就是这么的神奇,任何一个CSS属性都有值和单位,颜色也是如此。简单的统计了一下,CSS中能使用颜色的属性和颜色值相关的信息,简单地用图可以像下图那样来描述:

简单地说,能运用于color属性的颜色值都可以运用于CSS中任何会用到颜色的属性。在这篇文章中,我们主要介绍的是CSS中有关于颜色值相关的知识,如果你感兴趣的话,请继续往下阅读。

CSS颜色值的类型

CSS中指定颜色值有多种类型。有些是直接通过颜色通道指定sRGB颜色,比如最为熟悉的十六进制颜色表示法或rgb()函数。其他一些函数更易于编写和理解,比如hsl()lch()函数等,甚至还可以用一些颜色的名称,比如red

颜色的表示其实可以视为一个列表形式,有时也称为通道,即颜色空间中的轴。每个通道都有一个最小值和最大值(比如0~2550%~100%0~360deg等),并且可以取这两者之间的任何值。此外,每一种颜色都有一个透明通道,表示颜色的透明度。

简单地说,CSS中的颜色值的类型主要有:

  • <named-color>:用颜色名称定义的颜色,比如blackred
  • 关键词:用于颜色的关键词主要有currentColortransparent
  • <hex-color>:用十六制数来指定sRGB颜色,这与通常直接在计算机中编写颜色的方式类似
  • <rgb()><rgba()>rgb()函数通过直接指定红、绿、蓝通道来定义sRGB颜色,rgba()是在rgb()函数基础上增加了颜色的透明通道
  • <hsl()><hsla()>hsl()函数通过直接指定颜色的色相、饱和度和亮度来定义颜色,hsla()是在hsl()函数基础上增加了颜色的透明通道
  • <hwb()>HWB(白色-白色-黑色的缩写)是另一种指定颜色的方法,类似于HSL,它描述了一开始的色调,然后是一定程度的白色和黑色混合到基本色调
  • <lab()><lch()>Lab是由一个亮度通道和两个颜色通道组成的。在Lab颜色空间中,每个颜色用L(亮度)、a(从绿色到红色的分量)和b(从蓝色到黄色的分量)三个数字表示。而Lch分别表示了颜色的亮度、饱和度和色调
  • <gray()>:灰色是完全去饱和的颜色,gray()函数表示法简化了对这组常见颜色的指定,因此只需要一个数值参数,用来指定颜色的灰度
  • <color()>:该函数允许在特定的颜色空间中指定颜色
  • <device-cmyk()>:该函数是以CMYK(青色、品红、黄色和黑色)组合,在该设备上生成特定的颜色
  • <system-color>:根据用户操作系统来匹配颜色
  • color-mix():该函数接受两个<color>规范,并在给定的颜色空间中以指定的数量返回它们混合的结果
  • color-contrast():该函数首先使用一种颜色(通常是背景色),然后使用两种或两种以上颜色的列表,它从该列表中选择亮度对比度最高的颜色到单一颜色
  • color-adjust():该函数接受一个<color>规范,并通过指定的转换函数在给定的颜色空间中返回调整该颜色的结果
  • 颜色扩展:根据现有的颜色(在这称为“原始颜色”)在函数的目标颜色空间中生成颜色,它是<rgb()><rgba()><hsl()><hsla()><hwb()><lab()><lch()>的扩展颜色

上述所列的颜色,大部分已得到主流浏览器的支持,但部分颜色值的表示方法还未得到主流浏览器支持,甚至在未来还有可能会有相应的变化。在此暂时忽略未来的变化。就上面所列的颜色值表法方来自于不同的规范:

  • 颜色模块 Level 3:主要涵盖了<named-color>、颜色关键词两部分
  • 颜色模块 Level 4:主要涵盖了<rgb()><rgba()><hsl()><hsla()><hwb()><lab()><lch()><gray()>color()<device-cmyk()><system-color>
  • 颜色模块 Level 5:主要涵盖了color-mix()color-contrast()color-adjust()rgb()hsl()hwb()lab()lch()等函数

颜色关键词:<named-color>

在CSS中描述颜色的值有一些用英文单词命名的,它们不区分大小写。随着CSS规范不断的革新,能用英文单词命名的颜色值到目前为止差不多有147个。虽然这些颜色的值是用英文单词命名的,但也能找到对应的其他表示方法,比如十六进制、rgb()hsl()等。

在CSS中能用英文单词描述的颜色值如下表所示:

颜色关键词 颜色十六进制 实样 颜色关键词 颜色十六进制 实样 颜色关键词 颜色十六进制 实样
black(黑色) #000 silver(银色) #c0c0c0 gray(灰色) #808080
white(白色) #fff maroon(褐色) #800000 red(红色) #f00
purple(紫色) #800080 fuchsia(紫红色) #f0f green(绿色) #008000
lime(绿黄色) #0f0 olive(橄榄绿) #808000 yellow(黄色) #ff0
navy(藏青色) #000080 blue(蓝绿) #00f teal(青色) #008080
aqua(水绿色) #0ff orange(橙色) #ffa500 aliceblue(浅灰蓝) #f0f8ff
antiquewhite(古董白) #faebd7 aquamarine(海蓝) #7fffd4 azure(浅灰蓝) #f0ffff
beige(浅褐) #f5f5dc bisque(橘黄) #ffe4c4 blanchedalmond(杏仁白) #ffebcd
blueviolet(蓝紫) #8a2be2 brown(褐色) #a52a2a burlywood(原木色) #deb887
cadetblue(灰蓝) #5f9ea0 chartreuse(黄绿) #7fff00 chocolate(巧克力色) #d2691e
coral(珊瑚红) #ff7f50 cornflowerblue(矢车菊蓝) #6495ed cornsilk(玉米穗黄) #fff8dc
crimson(深红) #dc143c darkblue(深蓝) #00008b darkcyan(深青) #008b8b
darkgoldenrod(暗金) #b8860b darkgray(深灰) #a9a9a9 darkgreen(深绿) #006400
darkkhaki(暗黄褐) #bdb76b darkmagenta(深紫) #8b008b darkolivegreen(深橄榄绿) #556b2f
darkorange(深橙) #ff8c00 darkorchid(深兰花紫) #9932cc darkred(深红) #8b0000
darksalmon(深橙红) #e9967a darkseagreen(深海绿) #8fbc8f darkslateblue(暗灰蓝) #483d8b
darkslategray(墨绿) #2f4f4f darkturquoise(暗宝石绿) #00ced1 darkviolet(深紫罗兰) #9400d3
deeppink(深粉红) #ff1493 deepskyblue(深天蓝) #00bfff dimgray(暗灰) #696969
dodgerblue(遮板蓝) #1e90ff firebrick(砖红) #b22222 floralwhite(花白) #fffaf0
forestgreen(丛林绿) #228b22 gainsboro(浅灰) #dcdcdc ghostwhite(幽灵白) #f8f8ff
gold(金色) #ffd700 goldenrod(橘黄) #daa520 greenyellow(黄绿) #adff2f
grey(灰色) #808080 honeydew(蜜瓜色) #f0fff0 hotpink(亮粉) #ff69b4
indianred(印第安红) #cd5c5c indigo(靛蓝) #4b0082 ivory(象牙白) #fffff0
khaki(卡其色) #f0e68c lavender(淡紫) #e6e6fa lavenderblush(淡紫红) #fff0f5
lawngreen(草绿) #7cfc00 lemonchiffon(粉黄) #fffacd lightblue(淡蓝) #add8e6
lightcoral(浅珊瑚色) #f08080 lightcyan(淡青) #e0ffff lightgoldenrodyellow(浅金黄) #fafad2
lightgray(浅灰) #d3d3d3 lightgreen(浅绿) #90ee90 lightpink(淡粉) #ffb6c1
lightsalmon(浅肉色) #ffa07a lightseagreen(浅海绿) #20b2aa lightskyblue(浅天蓝) #87cefa
lightslategray(浅青灰) #778899 lightsteelblue(浅钢蓝) #b0c4de lightyellow(浅黄) #ffffe0
limegreen(酸橙绿) #32cd32 linen(亚麻色) #faf0e6 mediumaquamarine(中绿) #66cdaa
mediumblue(中蓝) #0000cd mediumorchid(间兰花紫) #ba55d3 mediumpurple(中紫) #9370db
mediumseagreen(间海绿) #3cb371 mediumslateblue(中暗蓝) #7b68ee mediumspringgreen(中春绿) #00fa9a
mediumturquoise(中海湖蓝) #48d1cc mediumvioletred(中紫罗兰) #c71585 midnightblue(午夜蓝) #191970
mintcream(薄荷乳白) #f5fffa mistyrose(粉玫瑰红) #ffe4e1 moccasin(鹿皮色) #ffe4b5
navajowhite(纳瓦白) #ffdead oldlace(浅米色) #fdf5e6 olivedrab(橄榄褐) #6b8e23
orangered(橙红) #ff4500 orchid(兰花紫) #da70d6 palegoldenrod(灰菊黄) #eee8aa
palegreen(苍绿) #98fb98 paleturquoise(苍宝石绿) #afeeee palevioletred(苍紫罗兰) #db7093
papayawhip(木瓜色) #ffefd5 peachpuff(桃色) #ffdab9 peru(秘鲁色) #cd853f
pink(粉色) #ffc0cb plum(李子色) #dda0dd powderblue(粉蓝) #b0e0e6
rosybrown(玫瑰粽) #bc8f8f royalblue(宝蓝) #4169e1 saddlebrown(马鞍棕) #8b4513
salmon(鲑肉色) #fa8072 sandybrown(沙褐色) #f4a460 seagreen(海绿) #2e8b57
seashell(贝壳白) #fff5ee sienna(赭色) #a0522d skyblue(天蓝) #87ceeb
slateblue(青蓝) #6a5acd slategray(青灰色) #708090 snow(雪白) #fffafa
springgreen(春绿) #00ff7f steelblue(铁青) #4682b4 tan(棕褐) #d2b48c
thistle(苍紫) #d8bfd8 tomato(番茄红) #ff6347 turquoise(蓝绿) #40e0d0
violet(紫罗兰色) #ee82ee wheat(麦色) #f5deb3 whitesmoke(烟白) #f5f5f5
yellowgreen(黄绿) #9acd32 rebeccapurple(利百加紫) #663399      

在CSS中,有些颜色的关键词(英文单词)不同,但对应的颜色是一样的,比如:darkgray = darkgreydarkslategray = darkslategreydimgray = dimgreylightgray = lightgreylightslategray = lightslategreygray = greyslategray = slategrey

其中rebeccapurple颜色能进入CSS颜色列表中,其中还有一个故事,如果你感兴趣的话,可以阅读@Eric Meyer的《rebeccapurple》一文。

在上表中列出的颜色,其中有 **16**个颜色最初来自于HTML:aquablackbluefuchsiagraygreenlimemaroonnavyolivepurpleredsilvertealwhiteyellow。除了这16个颜色被称为X11颜色集,其中X11颜色集的历史很有趣,如果感兴趣的话可以听@Alex Sexton 分享的《 Peachpuffs and Lemonchiffons》。

前面也提到了过了,英文命名的颜色值,也有对应的其他表示方式,比如十六进制(hex)、rgb()(或rgba())、hsl()或(hsla())。比如下图所示的crimson颜色,对应着#ed143drgb(237, 20, 61)(或rgba(237, 20, 61, 1))、hsl(349, 86%, 50%)(或hsla(349, 86%, 50%, 1)):

颜色关键词:currentColortransparent

在CSS中,通过关键词给颜色属性设置值除了上一节表格中提到的颜色值之外,还有两个关键词常被用于颜色值的设置中:**transparent**和 currentColor

transparent关键词表示一个完全透明的颜色,就相当于颜色透明通道为0。从技术上说,它是带有透明通道为0的黑色,即rgba(0,0,0,0)。正因为如此,当transparent关键词用于单一颜色属性(比如,colorborder-color等)上时不会有任何的问题,渲染出来的效果也是我们所期望的。但是用于CSS的渐变属性就会略有差异了。比如下面这段代码:

.element {
    background: linear-gradient(to bottom, red, transparent);
}

在Chrome、Firefox和Edge上,效果如下:

上图的效果正是想要的效果,但是在Safari下,效果就有问题了:

这是因为transparent被解析为rgba(0,0,0,0)。如果想修复它,那就得将该颜色的透明通道设置为0,比如该例是red,那么需要设置为rgba(255, 0, 0, 0)

.element {
    background: linear-gradient( to bottom, red, rgba(255, 0, 0, 0))
}

对于将一个颜色快速转换为rgba()hsla()总不是件易事,难免需要借助工具来转换。不过在后面的内容中将要介绍的color()函数,可能让事情变得更为简单,比如上例,如果用color()函数来描述的话,可以像下面这样:

.element {
    background: linear-gradient( to bottom, red, color(red alpha(0%)))
}

注意,transparent默认是是透明的黑色(black),即黑色的透明通道为0rgba(0, 0, 0, 0)hsla(0, 0%, 0%, 0)

CSS的currentColor这个关键词就更有意思了。它被称为是CSS中的第一个变量。因为currentColor是原始的color属性的计算值。简单地说,它的值和自身元素color的值相同。用一个简单的示例来描述:

.element {
    background-color: currentColor;
}

就该例而言,它将会是一个rgb(0,0,0),虽然.element元素上示显式设置color的值,但color是一个继承属性,即.element元素color属性继承了父元素的color值。因此background-color的值为rgb(0, 0, 0)

如果元素显式设置了color值,那么currentColor就会和color取值一样,上面的示例稍做修改,在.element上显式设置color

.element {
    color: #f36;
    background-color: currentColor;
}

这个时候background-color计算出来的值是#f36,如下图所示:

根据currentColor的特性,可以让我们的CSS代码变得更灵活,特别是在组件的构建上,例如下图所示:

我们来看一个实际示例:

尝试着将下拉选择框的值换成currentColor,再不断的修改color的值,你会看到你想看到的效果。如果你使用Safari浏览器查看的时候,你会发现transparent下,元素的渐变色对应的是rgba(0,0,0,0),和前面所说的是一致的。

sRGB颜色:rgb()rgba()#RRGGBB#RRGGBBAA

sRGB是色彩空间(模型)中的一种,维基百科是这样描述的:

sRGB色彩空间(standard Red Green Blue,标准红绿蓝色彩空间)是惠普与微软于1996年一起开发的用于显示器、打印机以及因特网的一种标准RGB色彩空间sRGB定义了红色、绿色与蓝色三原色的颜色,即在其它两种颜色值都为零时该颜色的最大值。

CSS中所说的sRGB颜色空间是指由绿三组值表示,它们标识了sRGB颜色空间中的一个点。通常情况下,在CSS中将其称为RGB,其中R表示的是红色、G表示是绿色、B表示的是蓝色。每个级分别由0~255的十进制数字来描述,或是00~FF的十六进制数字。其颜色范围总数是256 x 256 x 256 = 16777216

CSS中有关到颜色空间的概念并不会像色彩学中那么的重要,简单地说,即使你不懂任何色彩学知识,同样也能在CSS中用好颜色。比如,在CSS中对于sRGB颜色的表示方法就有很多种,比如十六进制,rgb()rgba()hsl()hsla()hwb()以及前面介绍的命名颜色和transparent

这里我们先来看rgb()rgba()。在CSS中,rgb()rgba()又被称为CSS的颜色函数,其中rgb()通过指定redgreenblue来指定一个sRGB的颜色。它有两种表示方法:

// 新语法规则
rgb() = rgb(<percentage>{3} [ / <alpha-value>]?) | rgb(<number>{3} [ / <alpha-value>])

// 旧语法规则
rgb() = rgb(<percentage>#{3} , <alpha-value>?) | rgb(<number>#{3} , <alpha-value>)

两者最大的差异就是,旧的语法在所有的参数之间有逗号,分隔,新的语法是透明通道和其他三个通道用/分隔(注意分隔线前后有空格)。在实际使用可以像下面这样:

.element {
    color: rgb(20% 50% 90%); //用百分比的话是0% ~ 100%
    border: 2vh solid rgb(90% 30% 70% / 65%); // 增加了透明通道,相当于rgba()
    box-shadow: 0px 0px 5px 6px rgb(0 220 255); // 用数字表示的话是0~255
    background-color: rgb(90 90 125 / .85); // 增加了透明通道,相当于rgba()
 }

你将看到的效果如下:

可能更多的开发人员喜欢的是带有,分隔符的语法规则:

.element {
    color: rgb(20%, 50%, 90%); //用百分比的话是0% ~ 100%
    border: 1px solid rgb(90%, 30%, 70%, 65%); // 增加了透明通道,相当于rgba()
    box-shadow: 0px 0px 5px 6px rgb(0, 220, 255); // 用数字表示的话是0~255
    background-color: rgb(90, 90, 125, .85); // 增加了透明通道,相当于rgba()
 }

不知道你发现了没有,现在rgb()函数使用的时候要是带上了第四个通道值(透明通道),其效果和rgba()将是一样的。

我们回过来简单的解释一下rgb()函数的语法规则:

  • <percentage>{3}(或<number>{3}:这个参数指定了颜色的红色(R)、绿色(G)和蓝色(B)三个颜色通道。它的值可以是百分比(0% ~ 100%)也可以是数字值(0 ~ 255
  • <alpha-value>:这个参数指定了颜色的透明通道(alpha)值,它的值同样可以是百分比(0% ~ 100%)也可以是数字(0 ~ 1),其中0%(或0)表示完全透明的颜色,100%(或1)表示完全不透明。

如果在rgb()中未显式设置<alpha-value>参数的话,被视为采用默认值100%,即颜色完全不透明。下面这个示例,通过改变rgb()不同的颜色通道值,可以得到不同的颜色:

有一点需要注意,如果在rgb()函数中使用的值超出规范所描述的值,比如小于0%(或0),大于100%(或255)的话,那么将会计算成两个极点值,即小于0%(或0)的会被计算成0%(或0),大于100%(或255)的会被计算成100%(或255)。比如:

rgb(120% 150% 190%)     ❯❯❯  rgb(100% 100% 100%)
rgb(-290 290 325 / .85) ❯❯❯ rgb(0 255 255 / .85)

对于透明通道的值也是如此,如果小于0%(或0)会被计算成0%(或0),如果大于100%(或1)会被计算成100%(或1)。

从语法规则上,我们可以知道,使用rgb()函数中表示sRGB颜色时,可能是数字也可以是百分比,但在浏览器渲染之后的计算值都会以数字值的方式表示,对于RGB三个颜色通道会以255做为基准值进行转换,对于A透明通道会以1为基准值进行转换。不同的浏览器之间会有略有差异,就是四舍五入的方式有差异,如下图所示:

由于历史遗留原因,rgba()函数还是会存在,但其语法和表现行为和rgb()函数相同,比如:

.element {
    border: 5px solid rgba(50 60 70 / .9);
    box-shadow: inset 5px 5px 5px rgba(40% 90% 100% / 60%);
    background-color: rgba(90,90,80,0.6);
    color: rgba(90%, 20%, 60%, 80%);
    text-shadow: 0 0 5px rgba(50 80 90);
    background-image: linear-gradient(45deg, rgba(90% 90% 10%), rgba(220,90,120))
}

你可能发现了,上面示例中rgba()函数中有的并没有显式的设置透明通道的值,但该值还是有效的,那是因为未显式设置透明通道值时,会将其默认为100%(或1)。

原则上来讲,在未来rgba()可以不再使用,因为rgb()直接可以实现rgba()等同的效果。简单地说,rgb()rgba()合并成一个函数,即rgb()

CSS中另一种表示sRGB颜色的常见方式是十六进制表示法,即#RRGGBB,这种表示颜色方法比用rgb()函数写出相同颜色的代码更短,比如rgb(255, 255, 255)就可以用#fff(或#ffffff)来表示。

十六进制颜色表示法在CSS中被称为 <hex-color>,其语法是一个<hash-token>令牌,其值由 34、**6**或 **8**个十六进制数字组成。 <hash-token>长得像下面这样

也就是说,十六进制颜色被写成一个哈希符 #,后面紧跟一些 0 ~ 9 数字或 **a ~ f**字母(字母没有大小写之分)。比如:

.element {
    color: #fff;
}

在使用十六进制来表示颜色时,给定的十六进制数字的数量决定了如何解码十六进制符号成RGB颜色。

六位数

哈希符#后面带了 6 位数,这六位数会分成 三对,从左往右每两位分别代表的是红色(R)、绿色(G)和蓝色(B)三个通道。每位值都可以是数字0~9或字母a~f组合而成。当十六进制采用六位数表示颜色值时,该颜色对应的透明通道(A)为默认值,即完全不透明。比如上图中的示例所示的颜色#00ff00对应的其实就是rgb(0 255 0)

三位数

三位数的十六进制颜色表示法是六位数十六进制颜色表示法的简化形式。当六位数的十六进制数中每对数值相同时,可以简写,比如#00ff00可以简写为#0f0,即#RRGGBB简写成#RGB。同样的,从左向往右每一位分别代表的是红色(R)、绿色(G)和蓝色(B)三个通道。同样的,每位值都可以是数字0~9或字母a~f

八位数

八位数的十六进制颜色表示法与六位数十六进制颜色表示法相似,不同的是,在六位数十六进制的基础上增加了 第四对 数,这一对数主要是用来指定颜色的透明通道,同样的,这对值可以是数字0~9或字母a~f。比如上图中的#00ff00cc颜色对应的就是rgb(0 255 0 / .8)

四位数

四位数的十六进制颜色表示法其实是八位数十六进制颜色表示法简写形式。比如#00ff00cc可以简写成#0f0c

比如下面这个小示例,尝试着修改每个输入框的值,会发现颜色有所改变:

如果你熟悉JavaScript的话,可以使用简单的脚本实现rgb()<hex-color>之间相互转换。比如@Paulina Hetman写的一个示例:

HSL颜色:hsl()hsla()

从Sketch制图软件中的拾色器中可以发现,除了RGB颜色模式之外,还会HSLHSB颜色模式:

注意,HSB又被称为HSV

在色彩世界中,HSLHSV也被称为色彩空间维基百科是这样描述的

HSLHSV都是一种将RGB色彩模型中的点在圆柱坐标系中的表示法。这两者都把颜色描述在圆柱坐标系内的点,这个圆柱的中心轴取值为自底部的黑色到顶部的白色而在它们中间的是灰色,绕这个轴的角度对应于“色相”,到这个轴的距离对应于“饱和度”,而沿着这个轴的高度对应于“亮度”、“色调”或“明度”。

这两种表示在目的上类似,但在方法上有区别。二者在数学上都是圆柱,但HSV(色相、饱和度、明度)在概念上可以被认为是颜色的倒圆锥体(黑点在下顶点,白色在上底面圆心),HSL在概念上表示了一个双圆锥体和圆球体(白色在上顶点,黑色在下顶点,最大横切面的圆心是半程灰色)。注意尽管在HSLHSV中“色相”指称相同的性质,它们的“饱和度”的定义是明显不同的。

因为HSLHSV是设备依赖的RGB的简单变换,(h, s, l)或 (h, s, v)三元组定义的颜色依赖于所使用的特定红色、绿色和蓝色“加法原色”。每个独特的RGB设备都伴随着一个独特的HSLHSB空间。但是 (h, s, l)或 (h, s, v)三元组在被约束于特定RGB空间比如sRGB的时候就更明确了。

从前面的内容可以得知,RGB是红色R、绿色G和蓝色B三种颜色相混,并且亮度相加在一起。该模式不管是对于设计师还是开发者而言,使用的时候都不直观,从一个rgb()函数(比如,rgb(220 30 90))或一个<hex-color>(比如#f9089f)字符串很难想象对应的颜色是什么。相比之下,HSLHSB对于使用者来说要更易于理解,使用的时候也能够获得更明确的预期。

HSLHSB颜色模型中,其每个字母都是一个单词的缩写,具有其自身的意义。

HSLHSB中的 H是英文单词 Hue的首字母,即色相,是色彩的基本属性,就是我们平常所说的颜色名称,比如红色、绿色、蓝色等。色相代表的并不是单一的颜色属性,它是人眼所能感知的颜色范围,这些颜色分布在一个平面的色相环上,颜色对应的色值处于0° ~ 360°之间,每一个角度可以代表一种颜色。

色相值的意义在于,可以在不改变光感的情况之下,通过旋转色相环来改变颜色。在实际运用中,只需要记住色相环上的六大主色,用作基本参照:360°)红、60°黄、120°绿、180°青、240°蓝、300°洋红,它们在色相环上按照60°圆心角的间隔排列,

HSLHSB中的 S是英文单词 Saturation,即饱和度,是指颜色的纯度或强度。主要用来表示颜色色相中彩色成份所占的比例,用0% ~ 100%来度量,100% 为最饱和的颜色,0% 为完全没有颜色的灰色:

在标准色轮上饱和度是从中心逐渐向边缘递增的。纯度即各色彩中包含的单种标准色成分的多少。纯度高的色彩色感强,即色度强,所以纯度亦是色彩感觉强弱的标志。不同色相所能达到的纯度是不同的,其中红色纯度最高,绿色纯度相对低些,其余色相居中,同时明度也不相同。

HSL中的 L是英文单词 Lightness,即亮度,是指色彩的明度,其作用是控制色彩的明暗变化。HSB中的 **B**是英文单词 Brightness,即 亮度;HSV中的 V是英文单词 Value,但它们和HSL中的L是有所差异的:HSL中的L是用来控制颜色中添加白的量,0%时颜色呈现为黑色,100%时颜色呈现为白色(无论色相和饱和度为多少);HSB(或HSV)中的B(或V)中用来控制白光强度,0%时颜色呈现黑色,100%时颜色呈现与饱和度相关

HSL中的黑色和白色是对立的,而HSB不是。当 HSLLightness 的值大于 50 并往上升的时候,和 HSB 中向白色靠拢的逻辑一致(亮度上升和饱和度下降);当 HSLLightness 的值小于 50 并往下降的时候,和 HSB 中向黑色靠拢的逻辑一致(亮度下降和饱和度不变)。

我想你现在对HSLHSB有了一定的了解了。我们回到CSS的世界中来。

在CSS中,我们可以使用hsl()hsla()函数来表达HSL的颜色,但至目前为止规范中并没有对应的hsv()hsb()函数。接下来我们只聊CSS中的HSL的颜色模式。

CSS的HSL指定的颜色也可以映射为RGB颜色。hsl()函数的语法和rgb()函数语法类似:

// 新语法
hsl() = hsl( <hue> <percentage> <percentage> [ / <alpha-value> ]? )

// 旧语法
hsl() = hsl( <hue>, <percentage>, <percentage>, <alpha-value>? )

// 其中<hue>
<hue> = <number> | <angle>

来看一个hsl()相关的小示例:

.element {
    color: hsl(250deg 10% 30%);
    border: 2vh solid hsl(60deg, 40%, 20%);
    box-shadow: 0px 0px 5px 6px hsl(230deg 40% 80% / 50%); // 增加了透明通道,相当于hsla()
    background-color: hsl(190deg, 50%, 90%, .8); // 增加了透明通道,相当于hsla()
}

你将看到的效果如下:

hsl()中的第一个参数是指颜色的色相<hue>,它可以是一个<number>,也可以是一个<angle>。在使用<angle>值时,除了可以使用deg单位之外,还可以使用CSS的其他角度单位,比如radgradturn。上面的示例,我们可以修改成下面这样达到相等的效果:

.element {
    /**
    * <hue> = <number> || <angle>
    * rad  = (π / 180) * deg
    * grad = deg * 400 / 360
    * turn = deg / 360
    */

    color: hsl(250 90% 50%);                                      /* ❯❯❯ hsla(250, 90%, 50%, 1)   */
    text-shadow:1px 1px 1px hsl(350deg 90% 40%);                  /* ❯❯❯ hsla(350, 90%, 40%, 1)   */
    border: 2vh solid hsl(1.047rad, 40%, 20%);                    /* ❯❯❯ hsla(60, 40%, 20%, 1)    */
    box-shadow: 0px 0px 5px 6px hsl(255.5556grad 40% 80% / 50%);  /* ❯❯❯ hsla(230, 40%, 80%, 0.5) */
    background-color: hsl(0.52778turn, 50%, 90%, .8);             /* ❯❯❯ hsla(190, 50%, 90%, 0.8) */
}

接下来的两个参数都是<percentage>,分别是指颜色饱和度S和亮度L。这两个参数的值都是介于0% ~ 100%之间:

  • 当饱和度的值是100%是完全饱和的,颜色是名亮的,0%时完全不饱和的灰色
  • 当亮度为50%代表正常颜色,而100%时是白色,0%是黑色
  • 如果饱和度或亮度小于0%或大于100%,则在转换为RGB颜色之间将它们固定在这些值上

hsl()中最后一个参数<alpha-value>是指颜色的透明通道,它的解释与rgb()函数的第四个参数相同。如果省略,则默认为完全不透明100%

hsl()函数和rgb()函数有点类似,<hue>的值可以是小于0和大于360的值,比如:

-100 ❯❯❯ 360 - 100 = 260 (大于0是顺时针旋转,小于0是逆时针旋转)
460  ❯❯❯ 360 + 100 ❯❯❯ 100 (相当于转完了一圈后,回到100位置)

hsl()中的另外三个参数,SLA取值都是百分比,当值小于0%时会取值为0%,当大于100%时会取值为100%,比如:

-10% ❯❯❯ 0%
190% ❯❯❯ 100%

比如下面这个示例代码:

.element {
    color: hsl(-250deg 10% 30%); 
    border: 2vh solid hsl(60deg, 140%, -20%); 
    box-shadow: 0px 0px 5px 6px hsl(230deg 40% 180% / 50%); 
    background-color: hsl(190deg, -50%, 90%, .8); 
    background-image: linear-gradient(to right, hsl(300 90% 30%), hsl(300 90% 40% / -20%));
}

打开浏览器查看器,通过颜色拾色器,可以看到结果如下图所示:

同样的,hsla()函数和rgba()类似,由于历史遗留问题,hsla()函数还是会存在的,其语法和表现行为和hsl()函数相同:

.element {
    color: hsla(300 30% 90% / 50%); /* ❯❯❯ hsl(300 30% 90% / 50%)*/
}

原则上来讲,在未来hsla()可以不再使用,因为hsl()直接可以实现hsla()等同的效果。简单地说,hsl()hsla()合并成一个函数,即hsl()

同样的,使用一些JavaScript脚本,可以将hsl()描述的颜色转换为rgb()#RRGGBB形式,比如@Gabi写的示例:

HWB颜色:hwb()

HWBHue Whiteness Blackness的简写,是RGB颜色空间的一种基于颜色的表示。HWB模型通常比HSL模型更直观(HSL模型本身被广泛认为比RGB更直观)。这是因为,HWB模型允许你选择一种色相盘上的一种颜色,然后根据自己需要将其与白色和黑色混合。就像混合颜色一样:

HWBHSL类似,每个字母都代表不同的意义:

  • H:和HSLHSV中的H相同,指的都是色相
  • W:指的是白色的程度,范围从0% ~ 100%(或0 ~ 1
  • B:批的是黑色的程度,范围从0% ~ 100%(或0 ~ 1

简单地说,HWB它描述了一开始的色调(H),然后是将一定程度的白色(W)和黑色(B)混合到基本色调,从而得到一个颜色

我们平时在开发者或者在制图软件中看到的颜色拾色器都是基于HWB颜色模式,由于它更直观。

在CSS中,我们可以使用hwb()函数来描述一个颜色,其语法和hsl()类似:

hwb() = hwb( <hue> <percentage> <percentage> [ / <alpha-value> ]? )

// 其中<hue>
<hue> = <number> | <angle>

hwb()函数的第一个参数指的是颜色的色相(Hue),它的解释和hsl()函数中H一样。

第二个参数主要用来指定混合的白色的数量,从0%(无白色程度)到100%(全白色程度)。类似地,第三个参数指定要混合的黑色数量,也从0%(无黑色程度)到100%(全黑色程度)。这两个参数的取值同样可以是小于0%100%的值,但当取值小于0%时,会以0%计算,同样地,取值大于100%时,会以100%计算。

第四个参数指定颜色的透明通道,它的解释与rgb()函数的第四个参数相同。如果省略,则默认为100%,表示完全不透明。

具体的使用如下:

.element {
    color: hwb(300 40% 20% / .80%);
}

使用hwb()描述的颜色在hwb取值不同时,颜色不同:

时至今日,hwb()函数还未得到主流浏览器的支持,在实际生产中时,如果需要使用hwb()函数,可以借助 postcss-preset-env或者使用PostCSS插件postcss-color-hwb

与设备无关的颜色:lab()lch()

颜色的物理测量通常表示为实验室颜色空间,由CIE在1976创建。从一个设备到另一个设备的颜色转换也使用Lab作为中间步骤。来源于人类视觉实验,Lab代表人类能看到的所有颜色。

Lab是一个中心亮度轴的直系坐标系。这个值通常写成无单位数;为了与CSS的其余部分兼容,它被写成百分比100%表示L值为100,而不是1.0L=0%为深黑(完全无光),L=100%为漫反射白(光源为D50白,色温为5000K的标准日光光谱,由一个完美的漫反射镜反射)。大于100的值对应高光,但在本规范中没有定义它们的精确颜色。有用的是,根据设计,L=50%是中灰色的,L的等距增量在视觉上是均匀间隔的:实验室的颜色空间在视觉上是均匀的a轴和b轴表示色调,沿a轴的正值为紫红色,负值为补色,为绿色。同样,沿着b轴的正值为黄色,负值为互补的蓝色(或紫色)。去饱和的颜色ab值较小,接近L轴;饱和色远离L轴。

LCHLab具有相同的L轴,但使用极坐标C(色度)和H(色调)。C是与L轴的几何距离,H是与a轴正方向的夹角,正方向的夹角是顺时针。在LCHLab中,如果两种颜色具有相同的L值,它们似乎具有相同的视觉亮度。

LCHLab本质是一样的,在LCHLab色相图上,c表示极径长度,h表示逆时针转过的角度,约定水平向右为0度:

注意,LCHLab中的L轴和HSL中的L是不相同的:

  • HSL中的L指的是明度(Lightness)
  • LCHLab中的L指的是感知明度(Luminance),在W3C中又称不相对明度(Relative Lumninance),主要用于量化人眼对光的明度的感知。常简为Luma

感知明度是一种颜色的可感知亮度。比如,在HSL中,sRGB颜色空间中的蓝色(#00f)总是比黄色(#ff0)看起来更深,但它们具有相同的L值。让我们把整个色调范围转换为感知明度范围,以便更清楚地看到这一点。

我们可以看到,每一种色调都有不同的感知明度。为了使其正常化,我们可以在每个色调中添加(减去)亮度,使其与中间灰色调#757575的亮度相匹配:

在实验室中,如果两种颜色有相同的测量值,它们有相同的视觉亮度。HSL和相关的polar RGB模型被开发出来,试图为RGB提供类似于LCH提供给Lab的可用性优势。

在CSS中,我们可以使用lab()函数描述Lab颜色空间,使用lch()函数描述LCH颜色空间。

lab()函数的语法规则和hls()函数相似:

lab() = lab( <percentage> <number> <number> [ / <alpha-value> ]? )

lab()函数的第一个参数指定了CIE的亮度。这是一个典型的介于0%(代表黑色)和100%(代表白色)之间的数字。第二个和第三个参数是Lab颜色空间中沿着ab轴的距离。这些值是有符号的(允许正负值),理论上是无界的(但实际上不超过±160)。第四个参数是可选值,和rgb()函数一样,用来描述颜色的透明通道,默认值为100%,表示完全不透明。

lab(29.2345% 39.3825 20.0664)  ❯❯❯ rgb(49.06% 13.87% 15.9%)
lab(52.2345% 40.1645 59.9971)  ❯❯❯ rgb(77.61% 36.34% 2.45%)
lab(60.2345, -5.3654 58.956)   ❯❯❯ rgb(61.65% 57.51% 9.28%)
lab(62.2345% -34.9638 47.7721) ❯❯❯ rgb(40.73% 65.12% 22.35%)
lab(67.5345% -8.6911 -41.6019) ❯❯❯ rgb(38.29% 67.27% 93.85%)

lch()函数是用来描述HCL颜色,它的语法规则和lab()类似:

lch() = lch( <percentage> <number> <hue> [ / <alpha-value> ]? )

第一个参数和lab()函数中的类似,指定CIE亮度,和lab()函数中的亮度参数解释相同。第二个参数是色度(大致表示“颜色的数量”)。它的最小有用值是0,而它的最大值在理论上是无界的(但在实践中不超过230)。如果提供的值为负值,则在计算值时为0。第三个参数是色相,它的解释和hsl()函数中的<hue>相似,但以不相同的方式将色相映射到角度,因为它们在感知上是均匀间隔的。相反,0deg点沿着正a轴(紫红色方向),90deg点沿着正b轴(芥末黄色方向),180deg点沿着负a轴(绿色青色方向),270deg点沿着负b轴(天空蓝色方向)。如果提供的值是负数,或大于或等于360deg,则将其设置为360deg。第四个参数同样是用来设置颜色透明通道,默认值为100%,则表示完全不透明。

lch(29.2345% 44.2 27)    ❯❯❯ rgb(49.06% 13.87% 15.9%)
lch(52.2345% 72.2 56.2)  ❯❯❯ rgb(77.61% 36.34% 2.45%)
lch(60.2345% 59.2 95.2)  ❯❯❯ rgb(61.65% 57.51% 9.28%)
lch(62.2345% 59.2 126.2) ❯❯❯ rgb(40.73% 65.12% 22.35%
lch(67.5345% 42.5 258.2) ❯❯❯ rgb(38.29% 67.27% 93.85%

特定的颜色空间指定颜色:color()

在CSS中,我们可以通过引用颜色配置文件来指定颜色。这可以是一个校准的CMYK打印机,或RGB色彩空间,或任何其他颜色或单色输出设备的特点。此外,为了方便起见,CSS提供了几个预定义的RGB颜色空间,比如srgbdisplay-p3a98-rgbprophoto-rgbrec-2020等。

在CSS,主要使用color()函数在特定的颜色空间中指定颜色(而不是其他颜色函数操作的隐式sRGB颜色空间)。color()函数的语法规则如下:

color() = color( [ <ident>? [ <number>+ | <string> ] [ / <alpha-value> ]? ]# , <color>? )

color()函数接受一个或多个逗号分隔的参数,每个参数指定一种颜色,如果之前的颜色无法显示,则稍后的颜色将充当回退(替代前者)。color()函数中的每个具体参数描述如下。

**<ident>**指的是<ident-token>,主要用来指定一个预定义的颜色空间,比如display-p3,也可以是一个由@color-profile规则定义的颜色空间。如果该参数未显式设置,它会采取默认的预定义颜色配置文件,即 sRGB颜色空间。 如果<ident>命名一个不存的颜色空间,则此参数表示无效的颜色。

第二个参数是<number> + | <string>,用来指定一个或多个<number>提供颜色参数接受的参数值,或者一个<string>提供颜色空间定义的颜色名称。其使用规则;

  • 提供的<number>多于颜色空间所接受的参数,则忽略末尾多余的<number>
  • 提供的<number>小于颜色空间所接受的参数,则缺少的参数默认为0
  • 提供的<string>,则<number>表示无效的颜色
  • 如果颜色空间定义了颜色的名称,那么提供<number>或提供了与颜色空间定义的任何颜色名称都不匹配的<string>,则此参数表示无效的颜色

第三个参数是一个可选参数,和rgb()函数中的<alpha-value>相同,用来指定颜色的透明通道,如果省略,则默认为100%,表示颜色完全不透明。

color()函数中各参数之后,可以使用任何CSS颜色语法提供最终的<color>参数。

如果对于规范中描述的color()函数难于理解的话,可以这样来理解:

color()函数接受一个颜色,可以应用几个“颜色修改器”或“颜色调整器”来修改给定的颜色

比如,我们要在#ffffff颜色上增加一定的黑色程度,我们就可以像下面这样使用:

.element {
    color: color(#f36 whiteness(100%));     /* ❯❯❯ rgb(255, 255, 255) */
    border: 2vh solid color(#f36 hue(196)); /* ❯❯❯ rgb(51, 201, 255)*/
    box-shadow: 0px 0px 5px 6px color(
        #f36 
        saturation(15%) 
        lightness(54%) 
        green(209) 
        blue(250) 
        whiteness(0%));                     /* ❯❯❯ rgb(0, 142, 250) */
    background-color: color(
        #f36 
        saturation(63%) 
        red(61));                           /* ❯❯❯ rgb(61, 89, 121) */
}

你或许已经发现了,上面示例中,color()函数引用的#f36,只是通过不同的调试器来修改颜色,不同的参数得到的最终颜色是不一样的。最终的效果如下:

能运用于color()函数中的颜色调试器主要有以下几种:

RGBA调试器

使用操作符,调整基本色的红色蓝色绿色透明通道。在没有操作符的情况下,设置基本颜色的红色、蓝色、绿色或透明通道。

[red( | green( | blue( | alpha( | a(] ['+' | '-']? [<number> | <percentage>] )
[red( | green( | blue( | alpha( | a(] * <percentage> )

比如我们有一个基本颜色#8cfeff,该基本颜色对应的RGB颜色值是rgb(140 254 255),其初始红色值是140,初始绿色值是254和初始蓝色值是255。如果我们在color()函数中显式指定:

color(#8cfeff red(220) green(100) blue(160)) ❯❯❯ rgb(220 100 160)

那么计算出来的颜色会是rgb(220 100 160)。即在基本颜色的red通道增加了80green通道减少了154blue通道减少95

HSL和HWB调试器

red()green()等函数相似,在color()函数中可以使用HSLHWB等来调整颜色:

[hue( | h(] ['+' | '-' | *]? <angle> )
[saturation( | s(] ['+' | '-' | *]? <percentage> )
[lightness( | l(] ['+' | '-' | *]? <percentage> )
[whiteness( | w(] ['+' | '-' | *]? <percentage> )
[blackness( | b(] ['+' | '-' | *]? <percentage> )

比如:

color(#8cfeff saturation(50%) lightness(35%) whiteness(36%) blackness(50%)) ❯❯❯ rgb(92, 127, 128) 

上面列出的具体函数的含义:

  • **hue**对应的是HSLHWB中的H,来调整基本颜色中的色相
  • **blacknesswhiteness**对应的是HWB颜色空间中的BW,用来调整基本颜色中白色和黑色的程度
  • **saturationlightness**对应的是HSL颜色空间中的SL,用来调整基本颜色中的饱和度和亮度

混合调节器

要使颜色更亮或更暗,tint()shade()是最简单的方法,它们的工作原理和混合白色或黑色一样的。

// 将基础颜色和白色混合
tint( <percentage> )  

// 将基础颜色和黑色混合
shade( <percentage> )  

// 将指定的颜色 与 给定的颜色混合
blend( <color> <percentage> [rgb | hsl | hwb]? )  
blenda( <color> <percentage> [rgb | hsl | hwb]? )  

其中blenda()blend()之间的唯一区别是,blenda()尊重两种颜色的alpha通道,而blend()只保留基本颜色的alpha通道。比如下面这个示例:

color: color(#8cfeff tint(50%) shade(30%) blend(#f36 50% rgb(90 90 90))); ❯❯❯ rgb(197, 115, 141) 

对比度调试器

contrast( <percentage>? )  

基于基本颜色调整颜色对比度。

color(#8cfeff contrast(70%))  ❯❯❯ rgb(20, 35, 36)

在使用color()函数的时候,调试器的顺序也是会影响颜色计算值,比如下面的示例:

background-color: color(#8cfeff contrast(10%) blue(128) green(255) red(140) saturation(32%)) ❯❯❯ rgb(175, 212, 171)
color: color(#8cfeff saturation(32%) red(140) green(255) blue(128) contrast(10%)) ❯❯❯ rgb(61, 105, 56)

@Tyler Gaw写的ColorMe很形象的演示了color()函数的功能。也可以在线快速基于基本颜色调整参数来修改颜色:

上面我们看到的示例都是使用color()函数是在默认颜色域sRGB下调整颜色。前面提到过了,可以在color()函数中显式指定颜色域,比如display-p3

color: color(display-p3 1 0.5 0)

注意,Display-P3颜色空间颜色要比sRGB颜色空间中的颜色更鲜艳:

也可以说,Display-P3sRGB的一个超集,大约要大35%

上图中,白线表示sRGB颜色空间的边缘,右上角所有的颜色都是sRGB颜色空间中没有的。

到写这篇文章时,Safari 97预览版本可以查看到display-p3的效果:

同样的,在color()函数中使用display-p3指定颜色空间时,也可以和sRGB颜色空间相互转换,如下图所示:

指定灰色:gray()

灰色是完全去饱和的颜色。gray()函数语法规则:

gray() = gray( <number>  [ / <alpha-value> ]? )

第一个参数指定灰度,等于CIE亮度,而第二个可选参数指定灰度的透明通道。

.element {
    color: gray(50);
}

注意:gray(a / b)相当于lab(a 0 0 / b)

设备相关的CMYK颜色:device-cmyk()

虽然屏幕通常使用RGB像素显示颜色,但打印机通常以不同的方式表示颜色。特别是,一种最常见的基于打印的颜色表示方法是使用 CMYK颜色模型,即青色品红黄色黑色的组合,在该设备上生成特定的颜色。

在CSS中,可以使用device-cmyk()函数来指定颜色:

device-cmyk() = device-cmyk( <cmyk-component>{4} [ / <alpha-value> ]? , <color>? )
<cmyk-component> = <number> | <percentage>

device-cmyk()函数的参数按顺序将青色、品红、黄色和黑色组合在一起,它们的值可以是0 ~ 1之间的<number>0% ~ 100%<percentage>。这两种取值方式是等同的,并且是线性地相互映射的。值小于0(或0%),或大于1(或100%),同样会有效,只不会小于0的值为计算为0,大于1(或100%)的会计算为1(或100%)。

第五个参数是指定颜色的透明通道,它的解释和rgb()函数中的第四个参数相同。第六个参数是用来指定回退颜色,在用户代理不知道如何准确地将CMYK颜色转换为RGB时使用。如果省略,它默认为CMYK颜色转换为RGBA

通常,基于打印的应用程序会将使用的颜色存储为CMYK,并以这种形式将它们发送到打印机。不幸的是,CSS不能做到这一点;各种CSS功能需要一个RGB颜色,以便合成(或混合)等。因此,CMYK颜色必须转换为等效的RGB颜色。这并不简单,比如从HSLHWB转换为RGB,精确的转换取决于输出设备的精确性。

如果用户代理拥有关于输出设备的信息,认为它可以准确的将CMYK颜色转换为正确的RGB颜色,那么device-cmyk()函数的计算值必呃面是RGBA颜色,否则,计算的值必须是回退颜色。

比如,下面的颜色是等价的:

color: device-cmyk(0 81% 81% 30%);
color: rgb(178 34 34);
color: firebrick;

注意:如果浏览器知道CMYKRGB颜色之间更精确的转换,那么这些颜色可能并不完全匹配。如果作者在他们的文档中使用任何CMYK颜色,建议他们在文档中只使用CMYK颜色,以避免任何颜色匹配的困难。

颜色函数

Web开发人员会经常使用颜色函数来帮助扩展其组件颜色。随着支持多个平台和用户喜好的设置越来越多,比如系统级别的暗黑模式设置,不需要手动设置颜色,就会根据用户的设置来改变UI的颜色。

到目前为止,Web开发人员常采用的是CSS处理器或calc()来计算HSL的值。但CSS处理器无法处理动态调整的颜色,所有当前的解决方案都受限于sRGB颜色域和HSL的感知限制(颜色在色轮中堆积,视觉亮度不同的两种颜色,如黄色和蓝色,可以具有相同的HSL亮度)。

在未来的CSS中,可以使用color-mixcolor-contrast以及修改颜色的方法来处理CSS的颜色值。

颜色混合计算:color-mix()

color-mix函数接受两个<color>规范,并在给定的颜色空间中以指定的数量返回它们混合的结果。如果没有特殊说明,否则在lch()颜色空间中进行混合。

color-mix函数的语法规则:

color-mix() = color-mix( <color>  <color> [ <number> | <percentage> | [ <color-function> <colorspace>? ]?] )

当指定纯数字或百分比时,它适用于所有颜色通道。比如将40%peru60%lightgoldenrod混合在一起,生成一个新的颜色,我们可以这样使用:

mix-color(peru lightgoldenrod 40%)

混合的计算是在lch()颜色空间中进行的。这是一个沿着中立的L轴的自顶向下的视图:

其计算方法如下:

基本颜色1:peru                   ❯❯❯ lch(62.253% 54.011 63.677)
基本颜色2:lightgoldenrod          ❯❯❯ lch(91.374% 31.415 98.821)
明度:L(lightness)的混合计算      ❯❯❯ 62.253 * 40/100 + 91.374 * (100-40)/100 = 79.7256
饱和度:C(chroma)的混合计算       ❯❯❯  54.011 * 40/100 + 31.415 * (100-40)/100 = 40.4534
色相:H(hue)的混合计算            ❯❯❯  63.677 * 40/100 + 98.821 * (100-40)/100 = 84.7634
最终结果:mix-color(peru lightgoldenrod 40%) ❯❯❯ lch(79.7256% 40.4534 84.7634)

下面这个示例在lch()颜色空间(默认)中将redyellow混合,每个lch通道的红色值占65%,黄色值占35%

mix-color(red yellow 65%);

其计算过程如下:

sRGB:red (#F00)                    ❯❯❯ lch(54.2917% 106.8390 40.8526)
sRGB:yellow (#FF0)                 ❯❯❯  lch(97.6071% 94.7077 99.5746)
L混合计算                            ❯❯❯  54.2917 * 0.65 + 97.6071 * 0.35 = 69.4521
C混合计算                            ❯❯❯  106.83 * 0.65 + 94.7077 * 0.35 = 102.5872
H混合计算                            ❯❯❯  40.8526 * 0.65 + 99.5746 * 0.35 = 61.4053
最终结果:mix-color(red yellow 65%)  ❯❯❯ lch(69.4521% 102.5872 61.4053)

注意:在色调和色度上进行插值计算,可以使中间颜色与端点颜色一样饱和

选择对比度最大的颜色:color-contrast()

这个函数首先使用一种颜色(通常是背景色,但不一定),然后使用两种或两种以上颜色的列表,它从该列表中选择亮度对比度最高的颜色到单一颜色。

color-contrast() = color-contrast( <color>  <color>#  )

比如下面这个示例:

color-contrast(wheat tan, sienna, var(--myAccent), #d2691e)

假设--myAccent的值为#b22222,其计算过程如下:

wheat (#f5deb3)  ❯❯❯ 背景色,感知明度 Luma = 0.749
tan (#d2b48c)    ❯❯❯ 颜色1,感知明度 Luma = 0.482 对比度(contrast ratio)1.501
sienna (#a0522d) ❯❯❯ 颜色2,感知明度 Luma = 0.137 对比度(contrast ratio)4.273
#b22222)         ❯❯❯ 颜色3,感知明度 Luma = 0.107 对比度(contrast ratio)5.081
#d2691e)         ❯❯❯ 颜色4,感知明度 Luma = 0.305 对比度(contrast ratio)2.249

颜色1 ~ 4几个颜色中,其中对比度最高的是5.081,即--myAccent取值为#b22222

修改颜色函数

在未来的CSS中,修改颜色的函数有很多种,比如color-adjust()rgb()hsl()hwb()lab()lch()函数。但其中rgb()hsl()hwb()lab()lch()函数和前面用来描述颜色值的<rgb><hsl><hwb><lab><lch>不同,可能大家会感到困惑。因为我们给color属性值时常会采用rgb()(对应的是<rgb>)这样的方式来表述。而我们这里所说的rgb()是个函数。

先来看color-adjust()

color-adjust() = color-adjust( <color> [ color-function <colorspace>? ]?] )

来看一个简单的示例:

color-adjust(peru lightness(-20%));

指的是peru(#CD853F)颜色在lch()颜色空间中,亮度(lightness)降低了20%。它的计算过程如下:

peru (#CD853F) ❯❯❯ lch(62.2532% 54.0114 63.6769)
调整亮度        ❯❯❯ 62.2532% - 20% = 42.2532%
结果:          ❯❯❯ lch(42.2532% 54.0114 63.6769) ❯❯❯ rgb(57.58% 32.47% 3.82%)

除了指定绝对坐标外,所有颜色函数还可以与“相对语法”一起使用,根据现有的颜色(称为原始颜色)在函数的目标颜色空间中生成颜色。该语法由关键字from<color>值和特定的颜色函数的可选数字坐标组成。为了计算原始颜色的坐标,每一个坐标都有一字母关键字和对应于颜色的字母。如果没有指定坐标,则该函数仅将原始颜色转换为目标函数的颜色空间。

常见的相对函数语法:

rgb() = rgb([from <color>]? <percentage>{3} [ / <alpha-value> ]? ) | rgb([from <color>]? <number>{3} [ / <alpha-value> ]? )

hsl() = hsl([from <color>]? <hue> <percentage> <percentage> [ / <alpha-value> ]? )

hwb() = hwb([from <color>]? <hue> <percentage> <percentage> [ / <alpha-value> ]? )

lab() = lab([from <color>]? <percentage> <number> <number> [ / <alpha-value> ]? )

lch() = lch([from <color>]? <percentage> <number> <hue> [ / <alpha-value> ]? )

当原始颜色出现时,以下关键字也可以相应的函数中使用。

  • r对应于原始颜色转换为sRGB后的红色通道,值是百分比
  • g对应于原始颜色转换为sRGB后的绿色通道,值是百分比
  • b对应于原始颜色转换为sRGB后的蓝色通道,值是百分比
  • alpha对应于原始颜色的透明度

上面所列的关键词主要运用于rgb()函数中。

  • h对应于原始颜色转换为sRGB后的色相,是个<number>值,其范围是0 ~ 360
  • s对应于原始颜色转换为sRGB后的饱和度,是个百分比值
  • l对应于原始颜色转换为sRGB后的亮度,是个百分比值
  • alpha对应于原始颜色的透明度

上面所列的关键词主要运用于hsl()函数中。

  • h对应于原始颜色转换为sRGB后的色相,是个数字值
  • w对应于原始颜色转换为sRGB后的白色程度,是个百分比值
  • b对应于原始颜色转换为sRGB后的黑色程度,是个百分比值
  • alpha对应于原始颜色的透明度

上面所列的关键词主要运用于hwb()函数中。

  • l对应于原始颜色的CIE明度,是个百分比值
  • a对应于原始颜色的CIE Lab中的a轴,是个数字值
  • b对应于原始颜色的CIE Lab中的b轴,是个数字值
  • alpha对应于原始颜色的透明度

上面所列的关键词主要运用于lab()函数中。

  • l对应于原始颜色的CIE明度,是个百分比值
  • c对应于原始颜色的浓度(chroma),即LCH颜色空间中的C
  • h对应于原始颜色的色相,即LCH颜色空间中的H
  • alpha对应于原始颜色的透明度

上面所列的关键词主要运用于lch()函数中。

它们在实际中可以这样的使用,比如:

rgb(from  indianred 255 g b) ❯❯❯ rgb(255 92 92)

indianred对应的rgb(205 92 92),上面示例使用rgb()函数,红色通道的值205255取代,而绿色和蓝色通道值保持不变,最终得到的值就是rgb(255 92 92)

比如我们快速找出原始颜色的互补色,那么就可以使用hsl()函数,将h增加180度即可,比如下面示例:

--accent:  lightseagreen;
--complement:   hsl(from var(--accent) calc(h+180) s l);

lightseagreen颜色对应的hsl(177deg 70% 41%),因此--complement最终对应的值是hsl(357deg 70% 41%)

特别声明:这里提到的CSS函数都还没有得到主流浏览器的支持,在未来也有可能会变动,这部分内容仅供扩展自己的视野。

小结

在这一章节中,主要和大家聊了Web中色彩的特性和CSS颜色值的使用。时至今日,在CSS中用来表达颜色值的方式有很多种,比如颜色关键词、<rgb()><hsl()><lab()><hwb()>#RRGGBB等方式。而且增加了很多处理颜色的函数,比如color()rgb()hsl()等。

话又说回来,虽然CSS中可以使用color属性给Web元素赋予丰富的色彩,但影响Web色彩的属性还有很多,比如CSS中的opacityfiltermix-blend-mode等。这里就不一一阐述了,如果你感兴趣,欢迎持续关注该系列的更新。