这篇文章来自于
Slicing SVG 9 Ways
,提供的思路方法确实不错,学习了下,文章没有逐字逐句翻译。主要是学习核心的思路和方法。
最近在一个项目中碰到一个问题,如下图所示:
demo地址
是一个卡片翻转的效果,仔细观察在卡片翻转的同时,在卡片的底部有一个阴影效果,阴影在卡片翻转过程中主要以下两个变化:
在卡片翻转的过程中阴影会随着卡片尺寸变化有个位移的变化。
阴影的尺寸也要跟随卡片的尺寸自适应。
当然要实现这样的效果,有很多方法。但是要同时兼顾性能和自适应的方法却不是很多。
我们要找的方案要同时能够兼顾下面这两个方面:
性能友好
。这个可以通过使用改变阴影的
transform
和
opacity
属性来实现,这两个属性的变化会直接使用设备的
GPU
来做渲染处理。
维护性好
。即阴影可以非常方便的通过代码来维护,如改变阴影的颜色等。
解决方案1:通过
box-shadow
来实现
首先想到可能就是通过使用
box-shadow
来实现。简简单单一行代码就可以实现阴影效果。
不过由于
box-shadow
是直接作用于元素本身,这意味着如果你想通过改变阴影的
blur
或者是它的
X
和
Y
值来实现阴影的动画效果。会触发网页不停的重绘,从而会影响网页的性能。
当然还可以通过利用改变元素伪元素如
:after
或者是
before
阴影的opacity来实现,但是灵活性却不是很好。
解决方案2:通过滤镜来实现(Blur Filter)
还有一种方法是通过使用CSS滤镜来实现即Blur Filter。比如
filter:blur(12px)
。
比如下图所示:
正常的图:
使用滤镜后:
我们可以通过控制滤镜的尺寸来实现阴影的动画效果,不过它和
box-shadow
同样有一个问题即改变它的相关值,会触发网页不停的重绘,从而会影响网页的性能,特别是在移动端更要注意性能的问题,稍有不剩,就会卡到爆。看来这也不是一个很好的方法。
解决方案3:SVG滤镜
在SVG中,使用滤镜也非常方便,通过下面一段代码就是用SVG中的高斯模糊滤镜来实现的一个模糊的效果:
version
=
"1.1"
xmlns
=
"http://www.w3.org/2000/svg"
width
=
"112"
height
=
"112"
>
<
filter
id
=
"blur-2px"
>
<
feGaussianBlur
in
=
"SourceGraphic"
stdDeviation
=
"2"
/>
</
filter
>
</
defs
>
<
rect
filter
=
"url(#blur-2px)"
stroke
=
"none"
fill
=
"#000000"
x
=
"6"
y
=
"6"
width
=
"100"
height
=
"100"
>
</
rect
>
</
svg
>
在高斯模糊滤镜中,
stdDeviation
使用来控制模糊程度的参数,数字越大越模糊。
实际如下图所示:
并且通过改变filter的相关属性很容易来控制模糊的效果,比如模糊的程度。如果直接的增大
stdDeviation
的值来改变模糊程度,我们可能会得到下面的效果,滤镜效果被剪裁了:
发生了什么,在W3C官网有这样一段描述:
The bounds of this rectangle act as a hard clipping region for each filter primitive included with a given ‘filter’ element; thus, if the effect of a given filter primitive would extend beyond the bounds of the rectangle (this sometimes happens
when using a ‘feGaussianBlur’ filter primitive with a very large ‘stdDeviation’), parts of the effect will get clipped. -
SVG Filter Effects Spec
主要的意思是:就是讲滤镜的效果区域。这些属性定义了滤镜起作用的矩形区域。滤镜效果不会应用在超过这个区域的点上。
在滤镜中,x,y的默认值是-10%,width与height的默认值是120%。所以如果你指定滤镜模糊程度的值超过默认的120%即滤镜起作用的区域,就会出现被剪裁的效果。
要不被剪裁,就需要相应的设置x,y以及width与height的值。
译者注
:其实在滤镜中还有一个重要参数需要设定即filter的
filterUnits
的值,
userSpaceOnUse
表示使用引用该filter元素的元素的用户坐标系统。如果不设置的话,那它的值默认为
objectBoundingBox
表示使用引用该filter元素的元素的包围盒的百分比做取值范围。
原作者文章中出现被剪裁的效果就是因为没有设置
filterUnits
的值为
userSpaceOnUse
而导致的,设置下这个值就不会出现剪裁了。
可以去这里看看实际例子:
demo
。
下面是重头戏了,来说说怎么使用高斯模糊滤镜来实现阴影动画效果。
border-image
我们这里会使用
border-image
这个属性来实现阴影的效果,具体关于
border-image
的详细说明可以去
这里
看看。
具体来我会在html中编写一个类名为shadow的元素来实现阴影效果,CSS如下:
.shadow {
position : absolute;
width : calc (100% + 12px );
height : calc (100% + 12px );
left : -6px ;
top : -6px ;
opacity : 0.3 ;
box-sizing : border-box;
border-style : solid;
border-width : 18px ;
border-image : url (images/shadow-2px.svg ) 18 fill stretch;
简单说明下代码:
这里设置元素的定位属性为绝对定位,宽高相对于父元素为100%,当然还需要把阴影的模糊值计算进去,这里模糊的值是12px,所以使用来calc 属性来计算元素的真实的宽高。
使用border-box 。这样可以改变盒模型的计算方式,border的宽度不会被计算到元素的宽高中去。
设置元素的边框为18px,下面的border-image要用到。
下面来说下border-image 是怎么来填充18px边框的:
border-image : url (images/shadow-2px.svg ) 18 fill stretch;
首先是引入已经制作好的SVG图片url(images/shadow-2px.svg)
18:用来设置边框的宽度,其单位是px,其实就像border-width一样取值,可以使用1~4个值,其具体表示四个方位的值,可以参考border-width的设置方式。
stretch:用来设置边框背景图片的铺放方式,类似于background-position,其中stretch是拉伸,repeat是重复,round是平铺,stretch为默认值。
fill:这里要说下border-image-slice 指定边框图像顶部、右侧、底部、左侧内偏移量。没有具体的单位值,只要给一个单纯的数字即可,当然也可以按照百分比来给设置值。作用就是把边框图像切成9个区域:4个角、4边区域和一个中间部位,即9宫格,如果不应用fill这个可选属性值的话,那么中间第九块格子被当做透明不见。所以这里使用fill属性,指定在没有边框图片的中间部分用模糊图片来填充。
所以这里使用SVG配合border-image 属性来实现了阴影的效果,并且可以通过改变阴影元素的相关值可以实现一些动画效果,性能也非常不错。当然更重要的是可维护性也不赖,可以通过编辑SVG文件来轻松的改变阴影的尺寸或者是颜色。
最后来看下一些使用这种方法来实习的阴影效果:
具体代码可以在这里查看 。
Emptied
1.6w
Starriers
JavaScript
4032
蚂蚁集团数据体验技术
JavaScript
Canvas