借助SVG滤镜实现CSS无法实现的阴影和模糊效果
source link: https://www.zhangxinxu.com/wordpress/2021/07/svg-filter-shadow-css-blur/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
by zhangxinxu from https://www.zhangxinxu.com/wordpress/?p=9986
本文欢迎分享与聚合,全文转载就不必了,尊重版权,圈子就这么大,若急用可以联系授权。
虽然CSS中有box-shadow
实现盒阴影,drop-shadow()
函数可以实现投影效果,filter
滤镜或者backdrop-filter
背景滤镜实现高斯模糊效果,但是依然存在某些场景,CSS是无能为力的。
此时,可能需要借助SVG滤镜“曲线救国”。
本文就通过几个案例,介绍下SVG滤镜实现CSS无法实现的阴影和模糊效果。
二、<img>元素的内阴影
例如,有一个图片元素,其图像是一个PNG透明图。
稍等,让我找一个能代表我的无版权PNG素材图。
10分钟后……
就这张了。
我们可以使用filter
滤镜中的drop-shadow()
函数轻松实现投影效果,例如:
<img src="fish.png" class="shadow">
.shadow { filter: drop-shadow(2px 2px 6px #000a); }
效果如下图所示:
但是,如果想要实现下图所示的内投影效果,则CSS就无能为力了。
因为drop-shadow()
函数并没有内投影的语法,要想实现上图所示的效果,唯有让图像镂空进行模拟,但是这样的处理成本比较高,因为需要对素材进行处理。
此时,可以试试使用SVG滤镜实现PNG图像的内投影效果。
SVG代码如下(复制到页面的任意问题):
<svg width="300" height="300" viewBox="0 0 20 20" style="position:absolute;left:-999px;"> <filter id="inset-shadow"> <!-- 投影偏移 --> <feOffset dx="0" dy="0"/> <!-- 投影模糊 --> <feGaussianBlur stdDeviation="6" result="offset-blur"/> <!-- 反转投影使其变成内投影 --> <feComposite operator="out" in="SourceGraphic" in2="offset-blur" result="inverse"/> <!-- 内投影附加黑色 --> <feFlood flood-color="black" flood-opacity=".95" result="color"/> <feComposite operator="in" in="color" in2="inverse" result="shadow"/> <!-- 把内投影显示在图像上 --> <feComposite operator="over" in="shadow" in2="SourceGraphic"/> </filter> </svg>
此时,只需要下面一行CSS就可以实现PNG图像的内投影效果了。
img { filter: url(#inset-shadow); }
眼见为实,您可以狠狠地点击这里:IMG图像的内阴影实现demo
二、原理简单介绍下
SVG滤镜,我之前介绍过2个比较深入的,一个是feDisplacementMap滤镜,还有一个是feTurbulence滤镜。
这里使用的滤镜要比上面2个滤镜基础,也更简单。
-
下面的表示投影偏移,这里没有任何偏移设置。
<feOffset dx="0" dy="0"/>
- 下面这段SVG代码作用是构建高斯模糊,
<feGaussianBlur stdDeviation="6" result="offset-blur"/>
其中stdDeviation表示标准偏差,
result
属性值是自己定义的,相同于把结果输出,然后给其他滤镜使用。会有下图所示的效果:
- 下面这段SVG是实现的精华所在:
<feComposite operator="out" in="SourceGraphic" in2="offset-blur" result="inverse"/>
其中feComposite表示混合滤镜,通常用来实现效果的混合,
operator
表示混合模式的操作是哪个,支持下面这些属性值:over | in | out | atop | xor | lighter | arithmetic
如果大家熟悉CSS的混合模式,或者是熟悉canvas中的globalCompositeOperation属性,上面几个值就不难理解。
operator="out"
表示原始图像和高斯模糊重叠的位置是透明的,于是,混合的结果就是,原始图像只有边缘高斯模糊的区域显示,就有下图所示的效果:是不是就是内投影效果了?
- 然而,上面的内投影有一个问题,那就是颜色,原始图是土黄色的,这内投影也是土黄色的,根本就看不出来投影,因此,我们还需要把内投影变个色,变成黑色。这个使用的就是feFlood滤镜。
<feFlood flood-color="black" flood-opacity=".95" result="color"/>
feFlood滤镜该滤镜用flood-color元素定义的颜色和flood-opacity元素定义的不透明度填充了滤镜子区域。
因此,呈现的就是一个色块:
- 接下来,只需要把这个黑色色块和土黄色内投影进行混合就好了,此时可以使用source-in模式,也就是重叠的地方混合,不重叠的地方透明。
<feComposite operator="in" in="color" in2="inverse" result="shadow"/>
此时,内阴影颜色就是黑色了,如下图所示:
- 至此,万里长征只剩最后一里路了,那就是把上面的黑色内阴影叠加在原始资源上,相关SVG代码如下所示:
<feComposite operator="over" in="shadow" in2="SourceGraphic"/>
operator="over"
表示直接覆盖在上面,in
表示在上面的输入资源,in2
表示在下面的输入资源,SourceGraphic表示应用滤镜的资源图形,在本例中,就是土黄色的鱼PNG图。于是就得到了最终的效果:
以上就是整个SVG滤镜实现的原理。
三、Firefox下背景高斯模糊
这个案例源自“京斯”的“在网页中实现标题栏「毛玻璃」效果”一文。
小伙子微信找到我,希望我可以帮忙传播下这种实现。
我呢,忙着做些其他不务正业的事情,一直拖到现在,抱歉,抱歉。
关于毛玻璃效果,之前我有介绍过,就是使用CSS backdrop-filter实现毛玻璃效果。
实现虽然简单,但是Firefox浏览器默认并不支持,需要开启支持实验性质属性,普通用户哪懂这个。
此时,就可以借助SVG滤镜让Firefox浏览器下也有毛玻璃效果。
此滤镜SVG代码如下:
<svg width="0" height="0" style="position:absolute;"> <filter id="blur" color-interpolation-filters="sRGB"> <feGaussianBlur stdDeviation="6" edgeMode="duplicate"/> <feComponentTransfer> <feFuncA type="discrete" tableValues="0 1"/> </feComponentTransfer> </filter> </svg>
feComponentTransfer滤镜这里只要是锐化边缘,不过却会产生圆角,不过不仔细看也注意不到。
相关实现代码如下,CSS部分:
.blur { background: -moz-element(#main) no-repeat; filter: url(#blur); }
这里使用了一个Firefix浏览器专属的<image>
数据类型element()
函数,这个函数我10年前就介绍了,整10年,有兴趣可以访问这里了解。
可以让元素作为背景图呈现,再配合模糊滤镜,就有了背景高斯模糊,也就是毛玻璃效果了。
对于这个案例,我专门做了个demo页面:SVG滤镜实现背景毛玻璃demo
Firefox和Chrome下均有效果,Chrome浏览器是backdrop-filter
滤镜实现的,Firefox就是SVG滤镜,可能有人手头没有Firefox浏览器,也可以查看下面这个我录制的MP4视频(不动点击播放):
四、还是写技术文章省心
还是写技术文章省心,没有什么限制,自由自在,不用顾忌什么。
所以,下半年业余时间重心还是放在技术文章的更新上吧,一些不务正业的事情,等以后退休了再说吧。
感谢大家的阅读,如果觉得内容还不错,欢迎分享与转发。
话说,今年的桃子好像特别好吃。
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK