深入理解CSS3 gradient斜向線性漸變
一、問題沒有想得那麼簡單
提問,使用CSS3 gradient漸變,在一個400*300
的div
層上實現一個(100px, 100px)
到(200px, 200px)
由紅到黃的斜向線性漸變,該如何實現?
//zxx: 這裡的討論CSS3漸變都是基於新式規範寫法,且忽略私有字首
我們可能知道水平漸變的實現,類似這樣:
{background-image:linear-gradient(left, red 100px, yellow 200px);}
效果可能近似這樣:
很自然的,那從(100px, 100px)
到(200px, 200px)
應該就是從左上角開始,應該是這樣子:
{background-image:linear-gradient(left top, red 100px, yellow 200px);}
效果可能近似這樣:
哇哦,帥氣,恩,應該就是我們想要的效果了!——
這顯然是不可能的,如果真這麼簡單,我也不會拿出來說了~
我們開啟Photoshop等繪圖軟體,畫一個符合上面要求的漸變,看看效果是:
與上面的CSS實現對比一下:
紅色區域大小明顯差很多,怎麼回事?
我只能告訴你,事情遠沒有你想的那麼簡單!
二、動用懶惰的慢思維,從頭開始
我們遇到問題,如果第一反應是求助別人,get的是表層的東西;如果自己深入分析,get的往往是實在的東西。第一種人看似好學,實際是個懶惰的人,勤快地使用輕鬆、耗費精力較少的快思維,這種人適合做銷售、公關,並不適合做技術;但並不表示他賺的票子會少。
題外話點到為止。深吸一口氣,來,吸…………好,現在我們重新審視CSS3 gradient線性漸變的標準寫法(因webkit不支援,這裡省略了to
):
background-image: linear-gradient( [ <angle> | <side-or-corner> ,]? <color-stop> [, <color-stop>]+ );
上面這種CSS語法我們經常見到,可能有人看不懂具體的意思,其實上面的些符號含義與正則表示式有很多一致之處:
[]
在正則中表示一個字元類,這裡,你可以理解為一個小單元。|
?
為量詞,表示0
個或1
個,言外之意就是,你可以不指定方向,直接漸變色走起。例如:background:linear-gradient(red, yellow);
就是從上往下的紅黃條紋效果。
+
也是量詞,表示1
個或者更多個。因此,終止顏色是不可缺少的。例如:linear-gradient(red)
是醬油命,白板。<>
中的是關鍵字,主要是讓開發人員知道這裡應該放些什麼內容。
線性漸變關鍵字
1. angleangle
表示漸變的角度,然而,這個角度變化千萬不能想當然理解,舉個例子:
如果angle
是45deg
, 還是由紅到黃的漸變,下面那個圖是正確的表現:
是A
呢還是B
呢還是C
呢還是D
呢?
這個要比女友拿著四件衣服讓你說哪個好看要簡單吧。
5秒鐘倒計時,5, 4, 3, 2, 1, ……
好了,答案是:C
親愛的朋友,回答正確了木有?
我保證,很多人都回答錯了(包括我自己),為什麼會犯錯?原因很簡單,“熟悉感效應”。
想讓人們相信謬誤有個可靠的方法,那就是不斷重複,因為人們很難對熟悉感和真相加以區別。——丹尼爾·卡尼曼
我們,譬如我,非常多次地接觸CSS3 transform
中的旋轉,rotate(45deg)
效果就是元素預設態順時針旋轉45°
;於是,這種熟悉感會讓我們覺得漸變的旋轉也應該如此。預設漸變從上到下,那麼旋轉45°
應該是D
啊(參見下gif示意),怎麼會是C
呢?
photoshop與CSS3走得越來越近了,我們可以從photoshop中找到答案。
從上圖那個圈中的圓環可以看出,漸變的角度與旋轉的那個角度完全不是一回事。線性漸變的這個角度為圓心為起點的發散方向。大圖示意就是:
2. side-or-cornerside-or-corner
中文意思就是“邊或角”,可選值有:
[left | right] || [top | bottom]
表示,你可以有如下的寫法或組合:left
, right
, top
, bottom
, left top
, left bottom
, right top
, right bottom
. 分別表示,從左往右,從右往左,從上往下,從下往上,從左上往右下,從……(都懂的,不全寫了)
其中的left top
(從左上往右下)正好我們一開始的例子使用了,現在看看,稍微想想,就知道我們使用錯了!
顯然,從(100,100)
到(300,300)
是個45度倍數角;而left top
的角度是直奔右下角的,而容器是400*300
,顯然,不是45度倍數角。根據我們上面對angle
的認識,角度應該是-45°
,-45°
為圓心網右下方向45
度的一條線,正好符合從(100,100)
到(300,300)
的方向!
3. color-stop
漸變關鍵顏色結點,語法為:
<color> [ <percentage> | <length> ]
中文解釋就是,顏色值+空格+百分比或長度值。例如red 100px
. 記住,這裡的顏色值只能一個,因此, red 100px 100px
是完全錯誤滴!
OK,現在我們定義重新梳理了一遍,現在實現一開始的漸變效果應該OK了吧,試試唄~
如下CSS:
{background-image:linear-gradient(-45deg, red 100px, yellow 200px);}
如下效果:
肉眼看上去好像那麼回事,我們來對比下photoshop中的正確實現:
額~ 貌似還是不對啊,而且差得更遠了,怎麼回事???
我只能告訴你,事情遠沒有你想的那麼簡單!
三、深入理解線性漸變的角度座標
上面的程式碼我們稍微修改下,加上-webkit
字首以及-moz
字首看看:
{background-image:-webkit-linear-gradient(-45deg, red 100px, yellow 200px);}
如下效果(非webkit核心截圖):
哎呀,貌似角度對了嘛!咋回事。
這是Chrome瀏覽器下的一個奇葩問題,最近,Chrome瀏覽器已經去掉了CSS3漸變的私有字首,但是,其中的解析也有了寫變化:
background-image:-webkit-linear-gradient(-45deg, red, yellow)
與
background-image:linear-gradient(-45deg, red, yellow)
在Chrome瀏覽器下的漸變方向居然是相反的!45deg
是正常的。
Firefox瀏覽器下也是如此,有字首和沒有字首方向相反!咋回事?
原因很簡單,CSS3目前還是草案階段!
從瀏覽器去掉字首前後的變化可以推測,之前,W3C的漸變座標是與photoshop中一致的,但是,後來,由於某些原因,修改了。
至於什麼原因,根據我草草的查詢,可能與下面幾個關鍵字之一有聯絡:animation/transition
動畫、write-mode
書寫方向、flex box
模型、以及radial-gradient
漸變等。
目前的規範是這麼說的:
using angles
For the purpose of this argument, ‘0deg’ points upward, and positive angles represent clockwise rotation, so ‘90deg’ point toward the right.
也就是:
使用angles
引數釋義如下,‘0deg’指向上面,同時正角度順時針旋轉,因此‘90deg’指向右邊。
我們畫一下就是:
可見,目前,規範的漸變座標系與photoshop是有差異的。
同時,也告誡我們,私有字首可不能亂用哦!
面向未來,顯然我們都要跟著規範走,於是有CSS:
{background-image:linear-gradient(135deg, red 100px, yellow 200px);}
效果為:
與PS圖比一下:
我去~怎麼還是有出入啊?——紅色區域大小明顯不一樣嘛!
我只能告訴你,事情遠沒有你想的那麼簡單!
四、深入理解角度座標與位置關係
對於斜向線性漸變,點到點的漸變可不是直接把點的橫座標放上去就可以的。因為當漸變傾斜的時候,漸變的起止點的座標也發生變化了。下圖是官方規範的一張示意圖,演示的是45deg
漸變的起止點以及方向。
記住一個關鍵點,漸變的起點和終點(預設)在過中心的漸變線的垂直線上,於是,我們就可以確定起點與終點的位置了。按照這個理解,我們就可以畫出400*300
div
上135deg
起始點在哪裡,然後再確定(100,100)
和(200,200)
的位置就輕鬆多了。
如下示意圖:
一圖頂前言,反正上面這張圖我是看懂了。於是,我們的座標起止點值其實就變成了,黑色括弧的長度以及紫色括弧的長度值分別多少!
雖然很多人不喜歡數學,但是幾何應該都還不錯,我們來一起算一下……
//zxx: 長度計算中……
結果為,起點:
100 * Math.sqrt(2) = 141.4213562373095;
終點為:
200 * Math.sqrt(2) = 282.842712474619;
CSS用上:
{background-image:linear-gradient(135deg, red 141.4213562373095px, yellow 282.842712474619px);}
效果:
與PS的效果比對下:
後面在補一個文字斜向漸變(作品見:Armor X2長圖)
<style>
h2{
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-image: linear-gradient(45deg, #ed1b2040%, #005aff 70%);
}
</style>
<h2>一段文字</h2>