1. 程式人生 > >深入理解CSS3 gradient斜向線性漸變

深入理解CSS3 gradient斜向線性漸變

一、問題沒有想得那麼簡單

提問,使用CSS3 gradient漸變,在一個400*300div層上實現一個(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等繪圖軟體,畫一個符合上面要求的漸變,看看效果是:
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. angle
angle表示漸變的角度,然而,這個角度變化千萬不能想當然理解,舉個例子:
如果angle45deg, 還是由紅到黃的漸變,下面那個圖是正確的表現:
漸變角度與呈現

A呢還是B呢還是C呢還是D呢?

這個要比女友拿著四件衣服讓你說哪個好看要簡單吧。

5秒鐘倒計時,5, 4, 3, 2, 1, ……

好了,答案是:C

親愛的朋友,回答正確了木有?

我保證,很多人都回答錯了(包括我自己),為什麼會犯錯?原因很簡單,“熟悉感效應”。

想讓人們相信謬誤有個可靠的方法,那就是不斷重複,因為人們很難對熟悉感和真相加以區別。——丹尼爾·卡尼曼

我們,譬如我,非常多次地接觸CSS3 transform中的旋轉,rotate(45deg)效果就是元素預設態順時針旋轉45°;於是,這種熟悉感會讓我們覺得漸變的旋轉也應該如此。預設漸變從上到下,那麼旋轉45°應該是D啊(參見下gif示意),怎麼會是C呢?
旋轉45度的效果 張鑫旭-鑫空間-鑫生活

photoshop與CSS3走得越來越近了,我們可以從photoshop中找到答案。

45度漸變在photoshop中的效果

從上圖那個圈中的圓環可以看出,漸變的角度與旋轉的那個角度完全不是一回事。線性漸變的這個角度為圓心為起點的發散方向。大圖示意就是:
漸變方向與角度的關係 張鑫旭-鑫空間-鑫生活

2. side-or-corner
side-or-corner中文意思就是“邊或角”,可選值有:

[left | right] || [top | bottom]

表示,你可以有如下的寫法或組合:
leftrighttopbottomleft topleft bottomright topright 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’指向右邊。

我們畫一下就是:
css3線性漸變現在的座標系

可見,目前,規範的漸變座標系與photoshop是有差異的。

同時,也告誡我們,私有字首可不能亂用哦!

面向未來,顯然我們都要跟著規範走,於是有CSS:

{background-image:linear-gradient(135deg, red 100px, yellow 200px);}

效果為:

 

與PS圖比一下:
作圖的效果 張鑫旭-鑫空間-鑫生活

我去~怎麼還是有出入啊?——紅色區域大小明顯不一樣嘛!

我只能告訴你,事情遠沒有你想的那麼簡單!

四、深入理解角度座標與位置關係

對於斜向線性漸變,點到點的漸變可不是直接把點的橫座標放上去就可以的。因為當漸變傾斜的時候,漸變的起止點的座標也發生變化了。下圖是官方規範的一張示意圖,演示的是45deg漸變的起止點以及方向。

45deg漸變示意圖

記住一個關鍵點,漸變的起點和終點(預設)在過中心的漸變線的垂直線上,於是,我們就可以確定起點與終點的位置了。按照這個理解,我們就可以畫出400*300 div135deg起始點在哪裡,然後再確定(100,100)(200,200)的位置就輕鬆多了。

如下示意圖:
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>