緣起
這是在做一個呼吸燈動效時遇到的問題,就是如何給SVG的圖形元素加上一些陰影的效果,比如外發光,比如内發光,比如投影,之前也有困擾,但是因為沒到非解決不可的程度,是以就暫時擱置了。對于發光這種效果,對于CSS3來說,很簡單的事情,一個box-shadow屬性可以解決所有問題,我曾經寫過一篇關于CSS3樣式的文章UI設計師進階技能——CSS3之樣式篇裡枚舉的非常全面,包括各個參數如何去和PS一一對應,不但能設定是外陰影還是内陰影,尺寸,X和Y的偏移,還可以多種效果去疊加,玩好了,當成是畫圖神器都是有可能的。
box-shadow的局限性
這是直接給一個100*100的div盒子定義了外發光後的效果,為了友善修改顔色,用了hsla的色值表示方法。
#box{
height:;
width:;
background: hsla(168,90%,45%,1);
border-radius: ;
box-shadow: hsla(168,90%,45%,1);
}
複制代碼
一個完美的外發光效果,試一下将box-shadow屬性定義到動畫規則中,會發生什麼:
/*定義一個透明度變化(hsla的a值改變)動畫規則*/
@keyframes outLight{
0%{box-shadow: hsla(168,90%,45%,1)}
100%{box-shadow: hsla(168,90%,45%,0.1)}
}
#box {
height:;
width:;
background: hsla(168,90%,45%,1);
border-radius: ;
animation: outLight ease infinite;
}
複制代碼
可以輕松實作這種透明度變化産生的“砰砰”動效。那再試一下改顔色,為了少寫一個動畫規則,我先不給盒子填充任何背景顔色,僅保留box-shadow效果。之是以用hsla色值表示方法,也是為了調整顔色友善,隻要改一下h值就可以了。
/*定義一個顔色變化(hsla的h值改變)動畫規則*/
@keyframes outLight{
0%{box-shadow: hsla(168,90%,45%,1)}
100%{box-shadow: hsla(220,90%,45%,1)}
}
#box {
height:;
width:;
border-radius: ;
animation: outLight linear alternate infinite;
}
複制代碼
變色也很OK,其他值的改變就不再做嘗試了。
這裡我試着做了一排依次按順序點亮的信号燈效果,任意一個時刻都是四個不同的顔色。
這裡,我如果想做一個圓環的外發光效果,抱歉,box-shadow屬性告訴你,這是天方夜譚,因為字面意思來講,box——盒子,作為盒子模型,支援的是一個整體的外觀,或者稱之為邊緣效果。
drop-shadow濾鏡的補充
drop-shadow
确切來說是濾鏡
filter
的一種,還有常見的模糊濾鏡blur,黑白濾鏡grayscale等等,這次先隻說這個投影。文法簡單:
.box {
height:;
width:;
border-radius:;
/*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)
,會發現投影效果也會發生變化。
drop-shadow
濾鏡是不像
box-shadow
屬性那樣支援多個設定疊加的,因為畢竟
filter
才是屬性,是以投影的濾鏡隻能設定一個。但是,濾鏡因為是加給實體的,不受什麼盒子模型影響,是以,當我的盒子是一個描邊而非填充樣式時
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>
複制代碼
這裡有一些特殊的文法,dx和dy通過字面意思容易了解,就是水準和垂直的偏移距離,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
濾鏡還能做什麼
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>
- 預設
的作用範圍為10%的溢出,當投影尺寸大時,需要修改x、y、width、height的值。
<filter>
轉載于:https://juejin.im/post/5cc013a9e51d456e2e656d70