# CSS渲染:CSS是如何绘制颜色的? 你好,我是winter,今天我们来学习一下CSS的渲染相关的属性。 我们在布局篇讲到,CSS的一些属性决定了盒的位置,那么今天我讲到的属性就决定了盒如何被渲染。 按照惯例,还是先从简单得讲起,首先我们来讲讲颜色。 ## 颜色的原理 首先我们来讲讲颜色,最常见的颜色相关的属性就是 `color` 和 `background-color`。 这两个属性没什么好讲的,它们分别表示文字颜色和背景颜色,我们这里重点讲讲颜色值。 ### RGB颜色 我们在计算机中,最常见的颜色表示法是RGB颜色,**它符合光谱三原色理论:红、绿、蓝三种颜色的光可以构成所有的颜色。** ![](https://static001.geekbang.org/resource/image/7f/a1/7f5bf39cbe44e36758683a674f9fcfa1.png) 为什么是这三种颜色呢?这跟人类的视神经系统相关,人类的视觉神经分别有对红、绿、蓝三种颜色敏感的类型。 顺便提一下,人类对红色的感觉最为敏感,所以危险信号提示一般会选择红色;而红绿色盲的人,就是红和绿两种神经缺失一种。其它的动物视觉跟人可能不太一样,比如皮皮虾拥有16种视锥细胞,所以我猜它们看到的世界一定特别精彩。 现代计算机中多用 0 - 255 的数字表示每一种颜色,这正好占据了一个字节,每一个颜色就占据三个字节。 这个数字远远超过了人体的分辨能力,因此,上世纪90年代刚推出这样的颜色系统的时候,它被称作真彩色。早年间还有更节约空间,但是精度更低的16色、256色、8位色和16位色表示法。 红绿蓝三种颜色的光混合起来就是白光,没有光就是黑暗,所以在RGB表示法中,三色数值最大表示白色,三色数值为0表示黑色。 ### CMYK颜色 如果你上过小学美术课,应该听过“红黄蓝”三原色的说法,这好像跟我们说的不太一样。实际上是这样的,颜料显示颜色的原理是它吸收了所有别的颜色的光,只反射一种颜色,所以颜料三原色其实是红、绿、蓝的补色,也就是:品红、黄、青。因为它们跟红、黄、蓝相近,所以有了这样的说法。 ![](https://static001.geekbang.org/resource/image/15/1b/15fefe9f80ec8e1f7bd9ecd223feb61b.png) 在印刷行业,使用的就是这样的三原色(品红、黄、青)来调配油墨,这种颜色的表示法叫做CMYK,它用一个四元组来表示颜色。 你一定会好奇,为什么它比三原色多了一种,其实答案并不复杂,在印刷行业中,黑色颜料价格最低,而品红、黄、青颜料价格较贵,如果要用三原色调配黑色,经济上是不划算的,所以印刷时会单独指定黑色。 对CMYK颜色表示法来说,同一种颜色会有多种表示方案,但是我们参考印刷行业的习惯,会尽量优先使用黑色。 ### HSL颜色 好了,讲了这么多,其实还没有涉及今天的主角:HSL颜色。接下来我们就讲一讲。 我们刚才讲的颜色是从人类的视觉原理建模,应该说是十分科学了。但是,人类对颜色的认识却并非来自自己的神经系统,当我们把阳光散射,可以得到七色光:红橙黄绿蓝靛紫,实际上,阳光接近白光,它包含了各种颜色的光,它散射之后,应该是个基本连续的。这说明对人的感知来说,颜色远远大于红、绿、蓝。 因此,HSL这样的颜色模型被设计出来了,它用一个值来表示人类认知中的颜色,我们用专业的术语叫做色相(H)。加上颜色的纯度(S)和明度(L),就构成了一种颜色的表示。 ![](https://static001.geekbang.org/resource/image/a3/ce/a3016a6ff178870d6dba23f807b0dfce.png) 在这里,我需要特别推荐HSL颜色,因为它是一种语义化的颜色。当我们对一张图片改变色相时,人们感知到的是“图片的颜色变了”。这里先容我卖个关子,具体的例子待我们讲完了渐变再看。 ### 其它颜色 接下来我们讲一讲RGBA,RGBA是代表Red(红色)、Green(绿色)、Blue(蓝色)和Alpha的色彩空间。RGBA颜色被用来表示带透明度的颜色,实际上,Alpha通道类似一种颜色值的保留字。在CSS中,Alpha通道被用于透明度,所以我们的颜色表示被称作 RGBA,而不是RGBO(Opacity)。 为了方便使用,CSS还规定了名称型的颜色,它内置了大量(140种)的颜色名称。不过这里我要挑出两个颜色来讲一讲:金(gold)和银(silver)。 如果你使用过这两个颜色,你会发现,金(gold)和银(silver)的视觉表现跟我们想象中的金色和银色相差甚远。与其被叫做金色和银色,它们看起来更像是难看的暗黄色和浅灰色。 为什么会这样呢?在人类天然的色彩认知中,实际上混杂了很多其它因素,金色和银色不仅仅是一种颜色,它还意味着一定的镜面反光程度,在同样的光照条件下,金属会呈现出更亮的色彩,这并非是用一个色值可以描述的,这就引出了我们接下来要讲的渐变。 ## 渐变 在CSS中,`background-image`这样的属性,可以设为渐变。CSS中支持两种渐变,一种是线性渐变,一种是放射性渐变,我们先了解一下它们的基本用法: 线性渐变的写法是: ``` linear-gradient(direction, color-stop1, color-stop2, ...); ``` 这里的direction可以是方向,也可以是具体的角度。例如: * to bottom * to top * to left * to right * to bottom left * to bottom right * to top left * to top right * 120deg * 3.14rad 以上这些都是合理的方向取值。 color-stop是一个颜色和一个区段,例如: * rgba(255,0,0,0) * orange * yellow 10% * green 20% * lime 28px 我们组合一下,产生一个“真正的金色”的背景: ```HTML
``` 放射性渐变需要一个中心点和若干个颜色: ``` radial-gradient(shape size at position, start-color, ..., last-color); ``` 当我们应用的每一种颜色都是HSL颜色时,就产生了一些非常有趣的效果,比如,我们可以通过变量来调整一个按钮的风格: ```HTML
123
``` ```JavaScript var btn = document.querySelector(".button"); var h = 25; setInterval(function(){ h ++; h = h % 360; btn.style.borderColor=`hsl(${h}, 95%, 45%)` btn.style.background=`linear-gradient(to bottom, hsl(${h},95%,54.1%), hsl(${h},95%,84.1%))` },100); ``` ## 形状 CSS中的很多属性还会产生形状,比如我们常见的属性: * border * box-shadow * border-radius 这些产生形状的属性非常有趣,我们也能看到很多利用它们来产生的CSS黑魔法。然而,这里我有一个相反的建议,我们仅仅把它们用于基本的用途,把border用于边框、把阴影用于阴影,把圆角用于圆角,所有其它的场景,都有一个更好的替代品:datauri+svg。 ## 总结 今天我们介绍了CSS中渲染相关的属性:颜色和形状。 我们重点介绍了CSS的颜色系统,从颜色基本原理讲解了RGB颜色、CMYK颜色和HSV颜色,我们还讲解了Alpha通道。 接下来我们又讲了颜色的一个重要应用:渐变,我们可以把渐变看作是一个更复杂的颜色,它非常实用,能够用渐变绘制很多的图像。 最后我们讲解了形状相关的属性,以及SVG应用的一个小技巧。 ### 思考题 ![](https://static001.geekbang.org/resource/image/0f/ac/0f6f4cc6d564df9986e0108cb8a427ac.jpg) 折衷鹦鹉是一种可爱的鸟类,但是雄性折衷鹦鹉居然是跟雌性颜色不一样!你能用JavaScript和canvas,把这只雄性折衷鹦鹉变成跟雌性一样可爱的红色吗?