深入理解css线性渐变

直到2011年末看到Lea Verou的CSS3 Patterns Gallery这篇文章,我才知道css渐变有多强大。只使用渐变去实现一些形状的想法是我接下来要做的多个css实验的开始。

最近,当我浏览CodePen上的demos时,我看到一个css3 色轮,当时我在想“我能不能只用一个元素和渐变去实现它呢”。接着,我开始尝试并且真的实现了。下面我会解释一下实现的原理。

一、分解

一个色轮,我们也可以叫它圆饼,首先将它水平二等分,接着再将每半五等分,总共分成十份。这意味着每一份的圆心角度数为360°/10 = 36°。Image

CodePen上的这个例子生动的展示了如何一层一层的实现多色背景。为了防止循环动画遇到性能问题,例子中还提供了停止按钮。

对于codePen的色轮以及这个帮助的例子而言,有必要讨论的地方是:

background: 
linear-gradient(36deg, #272b66 42.34%, transparent 42.34%),
linear-gradient(72deg, #2d559f 75.48%, transparent 75.48%),
linear-gradient(-36deg, #9ac147 42.34%, transparent 42.34%) 100% 0,
linear-gradient(-72deg, #639b47 75.48%, transparent 75.48%) 100% 0, 
linear-gradient(36deg, transparent 57.66%, #e1e23b 57.66%) 100% 100%,
linear-gradient(72deg, transparent 24.52%, #f7941e 24.52%) 100% 100%,
linear-gradient(-36deg, transparent 57.66%, #662a6c 57.66%) 0 100%,
linear-gradient(-72deg, transparent 24.52%, #9a1d34 24.52%) 0 100%, 
#43a1cd linear-gradient(#ba3e2e, #ba3e2e) 50% 100%;
background-repeat: no-repeat;
background-size: 50% 50%;
 
上面的代码使用了background的简语法指定了九个渐变背景层的position及color。
 
 

二、background 简写

大家都知道,一个元素背景的设定,可以是从上到下多个背景层重叠,背景色和最底层的背景一起定义。一个背景层包括以下几个方面:

1、<background-image> 

2、<background-position> / <background-size>

3、<background-repeat>

4、<background-attachment>

5、<background-origin>

6、<background-clip>

上例由于已经指定了九个背景层,并且这九个背景层都有同样的background-repeat和background-size设置而非默认值,所以上例将这两个属性定义在简写语法之外,使得无需重写九次这两个属性。

至于background-size,之所以会这样写另有原因:Safari17及以下版本不支持在background简写语法中包含background-size,此外firefox同样也不支持。当background-image是渐变时,background-size的两个值都应该指定,因为仅指定一个值,在不同的浏览器会有不同的显示效果(除非指定的值为100%,在这种情况下,这个值会被忽略而只显示默认值)

background-color设为#43a1cd,在它之上是使用css 渐变创建的九个不重复的背景层。这九个背景层的宽和高为这个元素的一半。

在这九个背景层中,最底层的背景水平居中位于底部,它只是firebrick red到firebrick red的渐变,最终显示为一个实色填充的矩形。其他八个背景层,要么是从透明渐变到一种实色,要么是从一种实色渐变到透明,这八个背景层中的每四个都由两个圆心角为2*36° = 72°的单片拼成的,同时单片之间重叠部分的圆心角为36°。

 

三、关于线性渐变

首先来了解一下线性渐变的定义,以便更好地理解渐变角度以及color stops 百分比值的计算方法。下面的例子能更好的让我们理解这个问题,点击例子中的点,改变渐变的角度。

 

image

渐变的角度是指纵坐标轴和渐变线(demo中的蓝色线)之间的顺时针夹角的角度。这种渐变角度的计算方式是针对新语法而言的,遗憾的是webkit 内核的浏览器还未支持这种新语法,但是相信情况会有所好转。计算渐变角度的旧语法是横坐标和渐变线之间逆时针夹角的角度,和trigonometric unit circle类似。

从我的数学背景来看,不得不说旧的方式对于我来说比较自然,但是新的方式和css的其他属性保持一致,例如,rotate transform,旋转角度值也是顺时针的。

这意味着使用标准语法和目前webkit支持的语法会得到两个不同的角度值。如果在使用渐变的时候需要标识浏览器标识的话,要清楚二者的转换。这个很简单,下面是二者的转换公式:

newSyntax = 90° - oldSyntax;
oldSyntax = 90° - newSyntax;
垂直于渐变线的线上的所有点的颜色是相同的。如果垂线位于与渐变角度相反的象限内,并且经过该象限的顶点,这条线是0%线(例子中的红线),它与渐变线的交点是渐变开始的点(S点)。如果垂线位于渐变角度所在的象限内,并且经过该象限的顶点,这条线是100%线(例子中的黑色线),它与渐变线的交点是渐变结束的点(E点)
image 

为了计算出任何一个P点的%值,可以从P点为起点画一条渐变线的垂线,垂点为I,接着计算出SI和SE之间的长度系数,那么这个点的%值是那个系数*100%

四、应用

那么如何将上面这个计算公式应用到彩虹色轮这个例子当中呢? 

首先,考虑创建圆心角为36度的单片渐变。下图是一张矩形图片,在矩形左下角,有一个角度为36度的蓝色部分。以矩形对角线的交点为原点画x坐标轴和y坐标轴。过原点画垂直于矩形中蓝色区域和透明区域分割线的垂线,这条线便是渐变线。可以看到,渐变线和纵坐标之间的角度是36度,因此渐变的角度是36度


Image(2)

现在在渐变角度所在象限相反的象限内,画一条经过象限顶点并且垂直于渐变线的垂线,这条线是0%线,接着在渐变角度所在的象限,画一条经过该象限顶点,并且垂直于渐变线的垂线,这条线是100%线。

矩形的对角线将他们各自分成两部分,AO和Bo是相等。BOE和AOS的角度也是一样的。因为他们是对顶角,另外,三角形BOE和AOS是直角三角形。这三点证明这两个三角形是全等的。相反,这证明So和Eo是相等的,因此SE的长度是EO或者SO的两倍。


Image(3)
 

注意:在进行下一步之前,先复习一下有关的三角形定理。直角三角形的直角所对的边是直角三角形的最长边,叫做直角三角形的斜边。其他两边中构成直角叫做直角边。直角三角形正弦等于直角边和斜边的系数。同一个角的余弦是另一条直角边和斜边的系数。


Image(4)
计算直角三角形BOE中EO的长度非常简单。如果设定矩形一边的长度为a,那么对角线BO长度的二分之一是a*sqrt(2)/2.角BOE等于角BOM和EOM的差,为45-36=9度。由于Bo也是直角三角形BOE的斜边,Eo的长度是(a*sqrt(2)/2)*cos9°。同样的计算方法SE的长度为a*sqrt(2)*cos9°。
Image(5)
现在由A点出发向直线PI画了一条垂线。ASID是一个矩形,SI的长度等于AD的长度。现在我们来看一下直角三角形APD。在这个三角形中,AP是斜边,长度为a。这意味着AD的长度为a*sin36°.但是SI等于AD,因此SI的长度也为a*sin36°.
既然现在知道SI和SE的长度,就可以计算他们的系数sin36°/(sqrt(2)*cos9°) = 0.4234。因此color stops的%值为42.34%。
用这种方式,实现了linear-gradient(36deg, #272b66 42.34%, transparent 42.34%)
计算其他背景层的%值也用同样的方式。

五、自动化计算工具

到现在为止,或许你会觉得实现彩虹色轮需要大量的计算。尤其是在需要更多不同角度的渐变时,会更糟糕。

虽然在创建彩虹色轮的实验中,我确实在纸上计算了每一步,但是我仅仅是赞成并不鼓励这样做。所以我做了一个简单的小工具去计算渐变盒模型中每个点的%值。你只需要点一下渐变模型,%值会出现在渐变盒模型的下方中心。

你可以改变渐变盒模型的尺寸,也可以改变渐变本身。它接受线性渐变的最新语法,用度数表述角的值,使用<side>值或者根本没有值描述渐变的方向。

六、结束语

css渐变非常强大,理解css渐变的原理对于创建那些过去只能用图片实现的纹理和形状是非常有帮助的。


原文地址:
http://hugogiraudel.com/2013/02/04/css-gradients/

posted on 2013-08-07 16:41  chilebaby  阅读(1493)  评论(0编辑  收藏  举报

导航