4

借助SVG滤镜实现CSS无法实现的阴影和模糊效果

 3 years ago
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.
neoserver,ios ssh client

by zhangxinxu from https://www.zhangxinxu.com/wordpress/?p=9986
本文欢迎分享与聚合,全文转载就不必了,尊重版权,圈子就这么大,若急用可以联系授权。

SVG滤镜与模糊和投影

虽然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

demo页面效果截图

二、原理简单介绍下

SVG滤镜,我之前介绍过2个比较深入的,一个是feDisplacementMap滤镜,还有一个是feTurbulence滤镜

这里使用的滤镜要比上面2个滤镜基础,也更简单。

  1. 下面的表示投影偏移,这里没有任何偏移设置。
    <feOffset dx="0" dy="0"/>

    鱼

  2. 下面这段SVG代码作用是构建高斯模糊,
    <feGaussianBlur stdDeviation="6" result="offset-blur"/>

    其中stdDeviation表示标准偏差,result属性值是自己定义的,相同于把结果输出,然后给其他滤镜使用。

    会有下图所示的效果:

    高斯模糊效果

  3. 下面这段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"表示原始图像和高斯模糊重叠的位置是透明的,于是,混合的结果就是,原始图像只有边缘高斯模糊的区域显示,就有下图所示的效果:

    source-out模式混合后的效果

    是不是就是内投影效果了?

  4. 然而,上面的内投影有一个问题,那就是颜色,原始图是土黄色的,这内投影也是土黄色的,根本就看不出来投影,因此,我们还需要把内投影变个色,变成黑色。这个使用的就是feFlood滤镜。
    <feFlood flood-color="black" flood-opacity=".95" result="color"/>

    feFlood滤镜该滤镜用flood-color元素定义的颜色和flood-opacity元素定义的不透明度填充了滤镜子区域。

    因此,呈现的就是一个色块:

  5. 接下来,只需要把这个黑色色块和土黄色内投影进行混合就好了,此时可以使用source-in模式,也就是重叠的地方混合,不重叠的地方透明。
    <feComposite operator="in" in="color" in2="inverse" result="shadow"/>

    此时,内阴影颜色就是黑色了,如下图所示:
    黑色内阴影效果截图示意

  6. 至此,万里长征只剩最后一里路了,那就是把上面的黑色内阴影叠加在原始资源上,相关SVG代码如下所示:
    <feComposite operator="over" in="shadow" in2="SourceGraphic"/> 

    operator="over"表示直接覆盖在上面,in表示在上面的输入资源,in2表示在下面的输入资源,SourceGraphic表示应用滤镜的资源图形,在本例中,就是土黄色的鱼PNG图。

    于是就得到了最终的效果:

    最终实现效果示意

以上就是整个SVG滤镜实现的原理。

三、Firefox下背景高斯模糊

这个案例源自“京斯”的“在网页中实现标题栏「毛玻璃」效果”一文。

小伙子微信找到我,希望我可以帮忙传播下这种实现。

我呢,忙着做些其他不务正业的事情,一直拖到现在,抱歉,抱歉。

关于毛玻璃效果,之前我有介绍过,就是使用CSS backdrop-filter实现毛玻璃效果

实现虽然简单,但是Firefox浏览器默认并不支持,需要开启支持实验性质属性,普通用户哪懂这个。

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视频(不动点击播放):

四、还是写技术文章省心

还是写技术文章省心,没有什么限制,自由自在,不用顾忌什么。

所以,下半年业余时间重心还是放在技术文章的更新上吧,一些不务正业的事情,等以后退休了再说吧。

感谢大家的阅读,如果觉得内容还不错,欢迎分享与转发。

话说,今年的桃子好像特别好吃。

1f60c.svg

(本篇完)1f44d.svg 是不是学到了很多?可以分享到微信
1f44a.svg 有话要说?点击这里


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK