【译】CSS 十六进制颜色揭秘

3,814 阅读23分钟

CSS 十六进制颜色揭秘

简介

作为一个长期在世界各地主持技术峰会的主持人,我有机会和许多技术传播者交流,我将这些人称为“专业的技术作者”,忙于他们的工作。

一个主题反复出现的是 CSS 中的颜色 —— 特别是它们在 CSS 的属性值中使用十六进制表示法。你可以在你的 CSS 中各个地方看见这些看起来怪怪的字符串:#FF0080#9AC0B3#B5CBE8。我的意思是 #WTF,不是吗?

虽然大部分的技术作者都会在某些时候遇到十六进制编码的颜色值,它通常情况下是一个模糊的问题,所以从来没有人花时间去解释他们。我听到最多的评论大都是这样的:

  • 我一直在使用十六进制编码的色值,但是我真的不明白
  • 其实我知道一些十六进制编码的色值代表什么颜色,但是我不知道为什么
  • 有时候我可以修改十六进制的编码来达到我想要的效果,但是我不理解它们是怎么工作的。
  • 使用一个像 #BADA55 这样的不易理解的十六进制编码是错误的吗?

好的,就拿最后一个来说,但是答案是否定的,不,使用 #BADA55 这样的十六进制表示颜色不是错误的。如果你是想要一个黄绿色,那么你就可以使用 #BADA55

CSS 中的颜色

在 CSS 中颜色无处不在,它们可以作为前景、背景、阴影、表格、边框、链接、底纹等等这些属性的值。正因为颜色对于 CSS 是如此的重要,所以我们需要一个通用、标准的方式来引用它们,以便在所有浏览器中得到相同的颜色,这样用户就可以看到作者希望展现的颜色。

在 CSS 中设置颜色有很多种方式,我们稍后会讨论其中的几种。但本文的重点是十六进制颜色,因为它具有明确性、一致性,而且还十分优雅。虽然它有这么多优点,但是有个缺点就是它并不是很直观。

物理学

让我们从色彩的基本原理开始:白光其实是由彩虹的所有颜色组成。知道 Roy G. Biv 吗?它是红、橙、黄、绿、蓝、靛、紫七种颜色的英文首字母缩略词,我们看到的白光仅仅是有这七种颜色混合组成的。

如果你认为这是一个笑话,那么你太年轻了
如果你认为这是一个笑话,那么你太年轻了

颜料

要了解颜色是如何工作的,让我们先来回顾一下颜料中的物理光线。

颜料的三原色
颜料的三原色

学习颜料的第一件事情就是你可以把原色组合成第二种颜色。例如,你可以将蓝色和红色混合在一起得到紫色。同样,还有其他的选择,你可以将红色和黄色混合成橙色,黄色和蓝色混合成绿色 —— 全新的第二种颜色。

颜料中的生成色
颜料中的生成色

你当时不知道的是它的成色原理:颜料减色法原理。也就是说,它们吸收或减去白光中的某些色光,只反射它们没有减去的光。

对于那些没有试验过的人来说,这意味着一个看起来是单一颜色的物体实际上不是那种颜色。因为物体吸收了所有的光波长,但是只反射回来一种颜色的光(我们看到的),它实际上是所有的颜色。换句话说,是除了它显示的颜色之外的所有颜色。我们看到的橘色实际上并不是橙色。虽然不符合常理,但事实如此。

在不知道它的物理特性的情况下,我们早都理解将两种或两种以上的颜色组合在一起会得到其他颜色,而且我们添加的颜色越多,新的颜色就越多,每种颜色都比原色更深。我们最终了解到,如果把所有的颜色混合在一起,我们最终会得到黑色,或者是非常接近黑色的颜色。我们现在知道,这是因为从原来的白光开始,随着越来越多的颜料被加入,越来越多的光被吸收或减去。所以,明显的是,光线越少 = 颜色越深。 提示:请记住这一点,这在后面将会很重要。

非常非常深的灰色就接近黑色
非常非常深的灰色就接近黑色

我们发现颜料混合的另一件事是,除了被混合的颜色外,混合颜色的比列也会影响结果。即同为蓝黄混合,黄色多一点,会产生一个淡淡的“春绿”,而蓝色多一点则会产生一个暗暗的“森林绿”。所以很明显,混合的比例也很重要。

色光

你明白了吗?那好,现在忘了它,因为所有的计算机屏幕都是基于光而不是颜料。颜料的知识只是为光学做准备,稍后你会感谢我的。事实证明,光学的物理现象是和颜料相同的,只是稍有不同(这是真的)。

就像上面讨论颜料一样,我们先从原色开始,在光学上它们是红色、绿色和蓝色。

我们一起来看,这可能有一点粗糙
我们一起来看,这可能有一点粗糙

就像颜料一样,我们可以将原色混合获得第二种颜色。并且,就和颜料一样,并且也有很多种混合结果。蓝光和红光混合得到名为 purple-y 的颜色,我们称之为洋红;绿光和蓝光混合得到名为 teal-y 的颜色,我们称为青色;好吧,很合理,有红灯了也有绿灯了……什么?!?

是的,最后一个确实和前面的不一样,并不像直观感受的那样,但是这就是光学的工作原理:红光和绿光相加得到黄光。

这是为什么呢?本来就是如此,光学的工作原理就是这样的。你可能会对此感到困惑,如果对此感到困惑,你可以咨询这里面的 专家

这是因为色光是加色法,和颜料相反。我们组合的光波波长越多,新的颜色就越多,直到所有颜色都以最大比例混合时 —— 最终将得到白光。很容易看出,我们得到的每一种混合色都比它的原色更亮。因此,对于颜料我们的推论是:光线越少 = 颜色越深,而对于色光则是:光线越多 = 颜色越亮

三种原色的光聚集在一起就成了白光
三种原色的光聚集在一起就成了白光

回到 CSS

在 CSS 中,我们要达到预期的颜色效果,我们需要一种方式,不仅指定选哪一种原色,而且还要指定每一种颜色的比例。也就是说,我们需要精确地指定多少红色、绿色和蓝色的光线相加以获得特定的颜色。嘿,这是物理学!

在计算机世界,值的范围一般是在 0-255 之间。当然,这是有原因的,但现在你可以不用在意。因为要解释二进制是如何工作的,是另一篇文章的内容。现在,请相信我,每种颜色的最小值是 0,最大值是 255,谢谢。

设置颜色的方法

虽然我在本文中提倡十六进制表示色值的方法,但我不能忽视这一事实,它决不是唯一指定 CSS 颜色的方法。在继续之前,让我们快速看看其他三种方法。

注意: 如果你对这部分的内容完全不感兴趣,你可以直接跳到下一主题,快速浏览。说真的,你不会错过任何关于十六进制的重要信息。这个小插曲主要是未来完整性,很大程度上是为了避免文末出现大量“但是,但是,但是...”的评论。

颜色名

通过颜色名设置颜色是一种简单的方式,所有现代浏览器都能解释各种颜色名,它们可以用作 CSS 属性值。很多名字都很有道理,比如 black(黑)、white(白)、red(红)、green(绿)、blue(蓝)、yellow(黄)、purple(紫)、orange(橙)等等。有些不是很明显,像 aquamarine(海蓝宝石),blueviolet(蓝紫色),cornsilk(花丝),khaki(卡其布)。然后有些是荒谬的,像 aliceblue(爱丽丝蓝)、lavenderblush(淡紫红)、burlywood(原木色)、和 gainsboro(淡灰色)。

问题是,颜色名不够灵活,也不常见。purple 只对应一种颜色,那就是“紫色”。如果你想要一个特定的紫色,比如“淡紫”、“薰衣草紫”,那它做不到。当然,有 “mediumorchid”、“plum” 和 “thistle” 这些名称可供选择,但这些可能并不是你想要的颜色,并且你怎么通过名称知道是什么颜色呢?正如刚才提到的,名称越奇特,颜色越不直观。我认为没有人能猜到 “peru” 是什么颜色。

例如,这是一个有红色背景的黄色文本,使用颜色名设置:

span.hilite { color: yellow; background-color: red; }

RGB

另一种方法被称为 RGB,对于……嗯,我希望你能解决那个问题。这种方法使用普通的数字,并且相当整齐地用十进制记数法或百分比指定每个颜色的比例。但这种方法,冗长并复杂;有额外的括号,逗号,和/或百分比符号,很容易写成不是你想要的颜色或者出错。

这是一个有红色背景的黄色文本,使用 RGB 设置:

span.hilite { color: rgb(255, 255, 0); background-color: rgb(255, 0, 0); }

或者

span.hilite { color: rgb(100%, 100%, 0%); background-color: rgb(100%, 0%, 0%); }

HSL

只是为了进一步把水搅浑,另一种方法称为 HSL,分别表示色调,饱和度,亮度。这种方法 —— 具有多种我不想使用的子方法,使用十进制值和百分比的值。十进制值表示色轮上的颜色从 0 到 360,其中 0 是红色,120 是绿色,240 是蓝色。百分比表示光的数量,其中 0% 是无色的,100% 是全色的。亮度百分比然后修改颜色的亮度或光度,其中 0% 是黑色的,100% 是白色的。我一直觉得这个方法有点混乱,根据我的经验,开发人员很少使用这种方法。

这是一个有红色背景的黄色文本,使用 HSL 设置:

span.hilite { color: hsl(60, 100%, 50%); background-color: hsl(0, 100%, 50%) }

十六进制表示

另外一种,十六进制记数法,通常是最流行的 CSS 颜色命名方法。它是具体的、一致的、紧凑的和精确的。使用三个字符的十六进制码在范围 00-FF 的指定 RGB 值,其中 00 是没有颜色和 FF 是所有颜色聚集在一起形成的白色。

这是一个有红色背景的黄色文本,使用十六进制色值设置:

span.hilite { color: #FFFF00; background-color: #FF0000; }

好了,这就够了,让我们继续来看!

快速的回顾一下

我知道你认为我在撒谎,但十六进制真的比你想象的容易。十六进制色值是基于十六进制(基数为 16)计算的。为了理解十六进制是如何工作的,你只需要理解十进制(基数为 10)是如何工作的。哦,等等,你已经做了!很好,让我们回顾一下。

请不要跳过这部分,好吗?我知道你理解十进制是怎样工作的,我想让你想一下为什么它能起作用。

十进制系统有十个单字符数字,0 到 9。你可以一直加一来获得下一个数字,但最终你将用完数字。当这种情况发生时,你把一个 0 放在这个位置,然后在左边再增加一位数。让我们来思考一下这句话的含义。

这里最重要的一点是,位置的名字表示它们中的数字的值,而每个位置的名称代表的最大值,在其右边的位置表示。在十进制中,最右边的位置称为“个位”,右边的第二个位置称为“十位”。数字“9”的意思是“九个一”,如果我们加上“1”(“一个一”),我们就用完了数字,所以我们就在个位放了一个 0,在十位放了一个 1,得到了两位数 10。

因此,十进制值 10,我们称之为“十”,实际上表示“一个十和零个一”。同样,十进制的 26 表示“两个十和六个一”,十进制的 33 表示“三个十和三个一”,十进制的 42 表示“四个十和两个二”。(当然, 这就是最终问题的答案 )。

十六进制的伟大之处在于它工作得很像十进制。确切地说! 不开玩笑、不夸张、并且你也只能选择使用十进制的方式理解十六进制。十六进制算术和十进制算术完全一样,它只有十六个字符数字而不是十个数字。

将 A ~ F 视为数字,对应十进制中的 10 ~ 15。当然,计算机是对你友好的才提出多出这六个数字,但(a)我们必须要学习他们,(b)如何在键盘输入。(c)那东西是什么,他们只是在字母最小的恶作剧。

换句话说,十进制值 10 用十六进制的一个数字 A 表示,这表示“十个一”。十六进制数字 B 表示“十一个一”,等等,直到 F,表示“十五个一”。

重复一遍,就和十进制一样,每一个位置的名字表示它们中的数字的值,每个位置的名称代表的最大值可以在其右边的位置表示。最右边的地方仍被称为“一”,我们现在可以数到 F(“十五个一”),右边起第二位被称为“16”。

十六进制加法:9 + 1 = a
十六进制加法:9 + 1 = a

数字“9”还表示“九个一”,但现在,如果我们加上“1”(“一个一”)的话,我们还没有用完的数字,所以我们可以在个位使用 A(“十个一”),只需要让十六显示为两位数。

就像十进制一样,你可以不断地增加一个数字来获得下一个数字,但是你仍然会用完数字。当这种情况发生时,你把一个 0 放在这个位置,然后在这位数的左边新增一位数。就和十进制一样,再让我们想想这句话的意思。

十六进制加法:f + 1 = 10
十六进制加法:f + 1 = 10

所以,10(数字 1 和数字 0)的十六进制值不是十,而是十六,因为它的表示“一个十六,零个一”。然而,就像十进制一样,任何两位数字的十六进制数字都可以用同样的方式读取和理解。这意味着,如果我们继续计数递增到十六的时我们就使用“F”,重点来了:我们可以使用十六进制的两位数从 00 到 FF 代表任何从 0 到 255 的十进制数

例如,在下面的图表中,十六进制的 14(也就是“数字一和数字四”)是十进制的二十,因为它实际上是一个十六(16)和四个一(1),在十进制中 16 + 4 = 20。十六进制的 A5 代表着一百六十五,因为因为它是十个十六(10 16 = 160)和五个一(1 5 = 5)。最终,要特别注意红色的线,因为他们是最终的范围和范围的中间点:十六进制的 00(数字零和数字零)是零,十六进制的 FF 是二百五十五(15 16 + 15 = 255),并且十六进制的 80(数字八和数字零)是一百二十八(8 16 + 0 * 1 = 128),是 00 和 FF 的中间值。提示:记住 “80” 是中间点,我们马上就要用到它。

十六进制计数,00 到 FF
十六进制计数,00 到 FF

请和我一起继续

让我们在这里喘口气,因为这个计数方案是整个事情的关键,是理解十六进制表示颜色的关键。但请不要让它更难理解;我不是在开玩笑,十六进制,真的真的真的和十进制工作原理一样。这些概念是完全相同的;在到达下一位数之前十六进制只不过是多了几个可用的数字。

在你继续之前,一定要理解这个概念。以下是一些十六进制转换为十进制的例子。

  • 1F = 一个十六和十五个一 = 十进制的 16 + 15 = 31
  • 2B = 两个十六和十一个一 = 十进制的 32 + 11 = 43
  • 41 = 四个十六和一个一 = 十进制的 64 + 1 = 65
  • AA = 十个十六和十个一 = 十进制的 160 + 10 = 170
  • F0 = 十五个十六和零个一 = 十进制的 240 + 0 = 240

看,一旦你掌握了窍门就很容易了。这只是数学。只不过是使用字母来表示数字。

因此,三个两位数的十六进制数字,从 00(0)到 FF(255),将在 CSS 颜色属性值中表示红色、蓝色和绿色的程度。

直观性

现在我们明白如何将基色混合和如何指定的每一个颜色的程度,应该明确的是,我们可以在整整六个十六进制数字产生任何颜色代码,从 #000000#FFFFFF,前面两位表示红色,中间两位表示绿色,最后两位表示蓝色 - 始终是 RGB 这个顺序。

我们可以用六个十六进制数字编码多少种颜色?嗯,这 FFFFFF 是十进制的 16777216 ,所以正确答案是“一堆”。

当我们指定 CSS 进制颜色代码之前,我们以“#”,称为英镑符号井号。CSS 就是这样知道下面是一个十六进制的颜色代码。另外,字母大小写不要紧,CSS 中 #a94cb3#a94cb3 是相同的。

了解这些之后,一些颜色代码你就应该知道怎样表达了,像黑色、白色和三基色。

十六进制的黑色、白色和三基色
十六进制的黑色、白色和三基色

这很简单,对吧?这是光的物理原理:在这些颜色代码中,每个 RGB 分量要么是“零”(00),要么是“全部”(FF)。所以,例如,#000000 表示黑色。看这些零;没有红色,没有绿色,没有蓝色 - 没有光源 - 没有光不就是黑色吗?(如果你说“暗的”,你被解雇了。)同样,#FF0000 代表红色。该代码指定完全红色,没有绿色,也没有蓝色。只有红色的光。只代表红色。没有其他的可能,必须是红色,正红。

不管你信不信,我们接着往下看,因为一旦你掌握了这个想法,其他颜色也开始变得直观了。现在你应该将十六进制代码看做的颜色,因为他们就是颜色。

考虑三基色,洋红(全红色,没有绿色,没有蓝色)青色(没有红色,全绿色,全蓝色),黄色(可直观的全红色,全绿色,没有蓝色)。创建这些颜色的十六进制代码现在应该是显而易见的。

十六进制颜色值
十六进制颜色值

好的,到目前为止,我们仍然只使用“没有”或“全部”值。但回想十六进制的 80(“数字八和数字零”)是 00 和 FF 的中间,所以我们现在应该能够使用这个值,方便地构建一些半光的颜色代码 —— 即代码创建深色调的初级和中级的颜色。嗯,我想知道那些会是什么样子的?可能像这样。

十六进制初级和中级半色调
十六进制初级和中级半色调

我们在这里做的,通过改变三个分量的值,仅仅是改变了光的数量,我们把代码放入每种颜色的代码中,从没有(00) 到一半(80) 到全部(FF),这个事实使我们有点顿悟。好吧,一个巨大的巨大的巨大的巨大的顿悟。实际上两个。

更高的数字 = 更多的光线 = 接近白色 = 明亮的颜色。

较低的数字 = 较少的光线 = 接近黑色 = 较暗的颜色。

这些真的很重要,请再读一遍。

小测验

让我们来做一些使用代码表示颜色的小测试,来吧,这将是很有趣的!用纯文字回答这些问题(不是十六进制代码),然后向下轮动一点来显示答案。

问题 1. 如果 #FF00FF 是亮红色并且 #800080 是暗红色,那么 #B000B0 是什么呢?

问题 2. 如果 #00FFFF 是亮青色并且 #008080 是暗青色(也被称为绿色),那么 #004040 是什么呢?

问题 3. 如果 #000000 是黑色并且 #ffffff 是白色的,那么 #010101#323232 代表什么颜色的范围呢?

…向下滚动

…接着向下

…继续

…再向下滚动一点

…马上就到了

答案 1: #B000B0 是中等亮度的 亮红和暗红色之间的地方,因为 B0 小于 FF 但超过 80。

答案 2: #004040 比暗青色暗的颜色,因为 40 小于 FF 和 80。

答案 3: #010101#323232五十种深浅不同的灰色,因为十六进制的 32 等于十进制的 50:3 16 + 2 1 = 50。

事实上,最后一个的问题使我们顿悟了一个更多并且细微,虽然不是特别伟大但又是非常重要的道理:

当所有三个色值相同时,不管值是多少,颜色都是灰色的

确实是这样的,#232323#a9a9a9#4b4b4b#2f2f2f#959595#dadada 和所有其他具有相同的 RGB 值的组合都是灰色 —— 有些更暗一些,一些更亮一些。而且,因为十六进制的 80 是 00 和 FF 的中间值,这意味着 #808080 是所有灰色的中间色。是的,“灰色”包括黑色 #000000 和白色 #ffffff;这意味着,真的有 256 种的灰色。

实际的例子

让我们来靠近一些实际的 CSS 颜色编码的示例。基于你对十六进制和颜色的新知识,你应该能够理解为什么这些十六进制的颜色值可以表示他们想要表达的颜色。看看这些 CSS 规则中的代码并且想一下这三对十六进制的数字表示什么颜色,你应该立刻能够回答上来。

例 1:在这里,文本的前景色设置为深蓝色并且背景色设置为偏浅一点的中灰色。

例 1
例 1

例 2:在这里,任何带有类名为“warning”的元素将设置为黄色背景红色文字(注意,根据上述规则,背景仍为灰色,假设这些都在同一个页面中。

例 2
例 2

例 3:在这里,正常的链接显示为蓝绿色的文本,而在悬浮样式设置为白色文字蓝绿色背景。(仍然在灰色页面背景下。)

例 3
例 3

例 4:最后,这个块的背景为浅棕色(淡黄色),一个棕色的边框,和深褐色的文本。(都在相同的灰色页面背景下。)

例 4
例 4

简写

我要说的是你可以将十六进制的六位 CSS 颜色值简写是为三位,但是请不要这样,这对平面设设计师不利。

首先,缩写通常会导致意外的颜色。只有当一个颜色值的两个十六进制数字相同,如 FF,88,或 22 时,缩写才是准确的。例如,#fff#ffffff 相同,#d09#dd0099 是一样的。但是如果原始颜色的十六进制数字就不相同,那么缩写的代码只会“看起来像”原始颜色,也就是说和原始颜色很接近,但是又不完全相同。例如:#080#008800 一样,但是肯定和 #008000一样的,#a4d#aa44dd 是相同的,和 #a040d0不同的

其次,即使是正确使用缩写,它也很少被一致地使用,在全局搜索中就可能出问题或者是无用的。如果你的 CSS 代码中使用 #4be 而其他人使用 #44bbee,稍后找到你需要你改变这个颜色,这就会产生匹配的问题。即使是简单的代码 #000#000000 也不荣易进行匹配和替换。

第三,颜色值的缩写仅仅能减少三个字节,这弊大于利。

总结

让我们来总结一下。这里要明确一点的是,十六进制并不难,和十进制不同的只是多了几个数字。你要记住你要处理的数据是的十进制表示是 0-255,但是写成十六进制的两位数表示就是 00-FF。一旦你接受了十六进制的基数是 16,你将会发现它与是基数为 10 的十进制原理是一样的。十六进制的颜色代码将表现的更为直观。

有些人明白了,但有些人还是不明白
有些人明白了,但有些人还是不明白

记住,它总是三对十六进制数字,总是以红-绿-蓝的顺序排列,更高的数字总是意味着更加明亮的颜色(反之亦然)。

现在花一点时间将你的手臂在你身后,拍拍自己的背,放松一下。你现在知道一些你的 98% 的同伴都不了解的知识!

参考文献

色彩部分

十六进制部分

工具

集成工具

集成工具通常允许您选择一个颜色并查看其代码,或者输入代码来显示颜色,例如谷歌浏览器的开发者工具有一个集成的颜色选择器,Mac 的 Sublime Text 也有一个颜色选择器的插件

其他

感谢!

谢谢你阅读这篇文章,我希望你在这一过程中获得了乐趣并学到了一些东西!评论或问题?可以在 dave@davegash.com 中联系作者,Dave Gash。


掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 AndroidiOSReact前端后端产品设计 等领域,想要查看更多优质译文请持续关注 掘金翻译计划官方微博知乎专栏