box-shadow/drop-shadow/feDropShadow 投影的前世此生

緣起

這是在作一個呼吸燈動效時遇到的問題,就是如何給SVG的圖形元素加上一些陰影的效果,好比外發光,好比內發光,好比投影,以前也有困擾,可是由於沒到非解決不可的程度,因此就暫時擱置了。對於發光這種效果,對於CSS3來講,很簡單的事情,一個box-shadow屬性能夠解決全部問題,我曾經寫過一篇關於CSS3樣式的文章UI設計師進階技能——CSS3之樣式篇裏枚舉的很是全面,包括各個參數如何去和PS一一對應,不但能設置是外陰影仍是內陰影,尺寸,X和Y的偏移,還能夠多種效果去疊加,玩好了,當成是畫圖神器都是有可能的。css

box-shadow的侷限性

這是直接給一個100*100的div盒子定義了外發光後的效果,爲了方便修改顏色,用了hsla的色值表示方法。html

#box{
height:100px;
width:100px;
background: hsla(168,90%,45%,1);
border-radius: 50px;
box-shadow:0 0 70px hsla(168,90%,45%,1);
}
複製代碼

一個完美的外發光效果,試一下將box-shadow屬性定義到動畫規則中,會發生什麼:動畫

/*定義一個透明度變化(hsla的a值改變)動畫規則*/
@keyframes outLight{
	0%{box-shadow:0 0 70px hsla(168,90%,45%,1)}
	100%{box-shadow:0 0 70px hsla(168,90%,45%,0.1)}
}
#box {
	height:100px;
	width:100px;
	background: hsla(168,90%,45%,1);
	border-radius: 50px;
	animation: outLight 1s ease infinite;
}
複製代碼

能夠輕鬆實現這種透明度變化產生的「砰砰」動效。那再試一下改顏色,爲了少寫一個動畫規則,我先不給盒子填充任何背景顏色,僅保留box-shadow效果。之因此用hsla色值表示方法,也是爲了調整顏色方便,只要改一下h值就能夠了。ui

/*定義一個顏色變化(hsla的h值改變)動畫規則*/
@keyframes outLight{
	0%{box-shadow:0 0 70px hsla(168,90%,45%,1)}
	100%{box-shadow:0 0 70px hsla(220,90%,45%,1)}
}
#box {
	height:100px;
	width:100px;
	border-radius: 50px;
	animation: outLight 0.7s linear alternate infinite;
}
複製代碼

變色也很OK,其餘值的改變就再也不作嘗試了。url

這裏我試着作了一排依次按順序點亮的信號燈效果,任意一個時刻都是四個不一樣的顏色。spa

這裏,我若是想作一個圓環的外發光效果,抱歉,box-shadow屬性告訴你,這是天方夜譚,由於字面意思來說,box——盒子,做爲盒子模型,支持的是一個總體的外觀,或者稱之爲邊緣效果。設計

drop-shadow濾鏡的補充

drop-shadow 確切來講是濾鏡filter的一種,還有常見的模糊濾鏡blur,黑白濾鏡grayscale等等,此次先只說這個投影。語法簡單:3d

.box {
	height:100px;
	width:100px;
	border-radius:50px;
    /*filter:drop-shadow 濾鏡*/
	filter: drop-shadow(0 0 30px hsla(168,90%,45%,1));
	background-color: hsla(168,90%,45%,1);
}
複製代碼

也能夠獲得一個完美的外發光效果,但這裏有個很大的坑,就是會受元素填充顏色的影響,好比,改掉背景顏色的透明度background-color: hsla(168,90%,45%,0.2),會發現投影效果也會發生變化。code

drop-shadow濾鏡是不像box-shadow屬性那樣支持多個設置疊加的,由於畢竟filter纔是屬性,因此投影的濾鏡只能設置一個。可是,濾鏡由於是加給實體的,不受什麼盒子模型影響,因此,當個人盒子是一個描邊而非填充樣式時cdn

filter: drop-shadow(0 0 8px hsla(168,90%,45%,1));
border:10px solid hsla(168,90%,45%,1);
複製代碼

就能獲得一個內外發光的圓環了。

這個搭配SVG可謂無往不利,好比,想給下面這種複雜的SVG圖形加一個投影,直接讓SVG使用定義好的濾鏡就能夠了。

原本就是一個普通平面的SVG圖形,加了filter="drop-shadow(0 10px 5px hsla(168,0%,45%,0.4))"的定義後,瞬間躍然紙上。並且投影的邊緣徹底就是圖形的邊緣,這但是box-shadow屬性無能爲力的事情。

來試一下對動畫的支持。

/*定義一個投影效果透明度變化(hsla的a值改變)動畫規則*/
@keyframes outLight{
0%{filter: drop-shadow(0 0 10px  hsla(168,90%,45%,1))}
100%{filter: drop-shadow(0 0 10px  hsla(168,90%,45%,0.1))}
}
複製代碼

依然能夠獲得動效。變色就不作了,也是支持的。

如今,新的需求又來了,我要給SVG中的圖形元素加投影,首先聲明,單個圖形元素是不支持使用drop-shadow濾鏡屬性的,已經踩過這個坑了,那還有救沒?有。

SVG量身定製的feDropShadow投影濾鏡

上面的投影濾鏡是CSS的filter屬性,只能把SVG當成一個圖片元素總體來處理,終極目標來着,SVG+CSS3的動畫對不對?這須要把SVG裏面的圖形元素單獨屬性賦值。SVG強大的<def>元素可讓這一切都變成現實。咱們要作的就是,首先定義一個id爲outLight濾鏡,語法以下:

<defs>
    <filter id="outLight">
    <!-- 定義了一個水平和垂直偏移距離爲0,大小爲10的外發光效果 -->
      <feDropShadow dx="0" dy="0" stdDeviation="10" flood-color="hsla(180,90%,40%,0.9)" />
    </filter>
  </defs>
複製代碼

這裏有一些特殊的語法,dxdy經過字面意思容易理解,就是水平和垂直的偏移距離,steDeviation是個什麼屬性?來看一下MDN文檔中對steDeviation的官方解釋:

The stdDeviation attribute defines the standard deviation for the blur operation.

用句簡單的話來解釋,就是投影的尺寸。
顏色的定義,屬性名爲flood-color,一樣,若是不hsla或者rgba這種自帶透明度定義的色值表示方法,須要調節透明度的話,則經過flood-opacity屬性來定義。

我使用了一個描邊的圓形經過filter:url(#outLight)語句來調用這個濾鏡,效果卻並不理想:

外發光效果的實現沒有問題,但很明顯的看出彷佛濾鏡做用的區域被截取了。追本溯源來找緣由,關於<filter>濾鏡的屬性值這樣寫道:

The position and dimensions of a filter may be specified using the following parameters: x, y, width, height. The default values are:

  • x: -10%
  • y: -10%
  • width: 120%
  • height: 120%

簡而言之,就是濾鏡默認做用範圍爲使用元素溢出10%,在上面這個案例中,由於發光的範圍較大,顯然10%的溢出是不夠的,既然默認值不合理,那就從新定義一下

<filter id="outLight" x="-50%" y="-50%" width="200%" height="200%">
複製代碼

這樣的話,我給到了200%的溢出範圍,這樣就解決了外發光半徑超出默認做用區域的問題。

獲得完美的外發光圓環。

能夠隨隨便便修改dx和dy的值,好比下面這種:

甚至讓投影徹底脫離本體

引伸:filter濾鏡還能作什麼

在深刻了解濾鏡以前,我一直把SVG定位爲矢量圖形,結合最多的也是平面風格的插畫,但當祭出濾鏡神器,忽然發現,能夠用SVG來讓純色填充的圖形變得有質感,好比增長紋理,好比增長浮雕效果。

下面這張圖片這樣看真的是平淡無奇,這是我在AI中繪製的基礎圖形。

燃鵝,當我按照下面圖層拆分後依次加上對應的濾鏡效果後

)

下面,就是見證奇蹟的時刻:

瞧這凹凸有致浮雕效果,瞧這底部細膩的紋理,是否是很難想象,在SVG中不過是下面這兩句濾鏡定義來實現的:

<!-- 給底層增長噪點效果的濾鏡 -->
<filter filterUnits="objectBoundingBox" id="noise">
	<feTurbulence baseFrequency="0.5" id="c2" in="c1" numOctaves="10" result="c2" stitchTiles="noStitch" type="fractalNoise">
	</feTurbulence>
	<feComposite in="c2" in2="SourceAlpha" operator="in"></feComposite>
</filter>
<!-- 模糊濾鏡 頂部高光和底部陰影均可以使用 -->
<filter id="blur">
<feGaussianBlur in="SourceGraphic" stdDeviation="5" />
</filter>
複製代碼

放幾個最終的效果來show一下技巧:

旋轉效果

閃爍效果:

關於<filter>深刻了解的話,應該有意思的地方還有不少,目前我能徹底弄明白只有投影和模糊,等徹底搞清楚以後,會來一篇單獨介紹濾鏡的專題。由於投影能夠徹底follow本體的變化,好比隨便來個最簡單的縮放:

另外關於利用濾鏡作動效的創意,還在左思右想中,這又是另一篇了。

小結一下
  • 經過<defs> <filter><feDropShadow ……/> </filter> </defs>的語法來定義一個投影效果的濾鏡。
  • 默認<filter>的做用範圍爲10%的溢出,當投影尺寸大時,須要修改x、y、width、height的值。
相關文章
相關標籤/搜索