SVG-让世界变得柔软

菠萝看到一个效果非常喜欢,当图形靠近时有一种类似于水滴融合在一起的感觉,不会像平时的图形那样生硬地互相遮挡,看了网上一些资料之后尝试着做了下面这个demo。

如果你也喜欢这个效果,可以继续看下菠萝翻译的下面这篇文章,有些地方可能会因为理解不到位有些差异,有兴趣的戳英文原文,文章中的GIF也在原文中有相关代码链接。

正文:《The Gooey Effect》 by LUCAS BEBBER

前阵子, Chris写了一篇关于《Shape Blobbing in CSS》,呈现出来的效果非常棒,背后的实现技术也相当机智。但是这种使用CSS常规滤镜的方法有它明显的缺点:没有透明度、水滴内不能展示内容,很难使用除了黑白之后的颜色等等。

刚好这些天我研究了一下SVG的滤镜,用来解决CSS方式的大多数问题非常方便。这里你可以看到一个带胶粘效果的菜单,我做了演示的效果:

SVG滤镜基础讲解

SVG滤镜功能非常强大,所以这个话题涉及的内容比较泛,这里我们只介绍那些基础的属性来理解它是如果实现这个效果的。

我们可以在大多数的浏览器中,把SVG滤镜通过CSS应用到常规的DOM元素上。

下面是定义滤镜的基本语法。

<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
  <defs>
    <filter id="name-your-filter-here">
      ...          
      <!-- insert filters here -->
      ...
    </filter>
    ...
  </defs>
</svg>

把SVG滤镜应用到一个DOM元素。

.selector {
  filter: url('#name-of-your-filter-here');

  /* you can also load filters from external SVGs this way: */
  filter: url('filters.svg#name-of-your-other-filter-here');
}

在某些浏览器中,你可能需要给filter属性加上私有前缀才能使用。

一个元素可以包含一个或多个滤镜基元,例如模糊、颜色转换、阴影等。

下面我们先看一些例子。

<filter id="blur">
  <feGaussianBlur in="SourceGraphic" stdDeviation="3"/>
</filter>

这个滤镜会对应用的对象做一个简单的3px的模糊。注意一下in="SourceGraphic"属性。

  • in属性定义了滤镜基元的输入。
  • SourceGraphic则是返回元素的原始滤镜图形的关键字。
  • 所以这意味着模糊滤镜的输入资源是对象的原始图形,很直观。

下面我们来看一个很普通但是复杂很多的效果——一个阴影滤镜。这个例子将清楚地展示如何把多个滤镜基元链接起来。

<filter id="drop-shadow">
  <feGaussianBlur in="SourceGraphic" stdDeviation="7" result="shadow" />
  <feOffset in="shadow" dx="3" dy="4" result="shadow" />
  <feColorMatrix in="shadow" mode="matrix" values="0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 0 0.6 0" result="shadow" />
  <feBlend in="SourceGraphic" in2="shadow" />
</filter>

先看一下第一个滤镜基元中的result属性和后面的in属性。通过result属性你可以给一个滤镜基元的输出结果命名,然后把这个结果替代原始的图形应用给下一个滤镜基元。在这个示例中,这些步骤将先模糊一个对象,使模糊的对象变暗,再移动这个被模糊和变暗的对象。

注意下最后一个元素的基元,它的意思是一些滤镜基元可以有多个输入(in2参数),你可以在多个滤镜基元的任何点多次调用SourceGraphic。在这个示例中,最后一个滤镜基元调用了SourceGraphic关键字和shadow,将原始的图形放在我们画出的阴影上方。

现在已经介绍完了SVG滤镜的基础知识,下面我们看一下如何实现胶粘效果。

见证奇迹的时刻

CSS实现方法基本的原理在这里讲过了,简而言之,这个想法的关键就是模糊两个或者多个的对象并增加对比度,很简单但是效果很酷炫。

但是,正如我们之前看到的,它依然就很多缺点:

  1. 对比度改变了对象原始的颜色,使得你很难运用除了黑白之外的颜色;
  2. 把内容也一起模糊了,导致无法使用;
  3. 容器需要一个背景颜色,所以没有透明度。

总之,这些缺点使得这个效果很鸡肋。

但是有了SVG滤镜的话,我们就可以实现很多CSS滤镜无法单独实现的效果,比如我们可以只提高alpha通道的对比度避免改变对象自身的颜色,我们可以使用前面使用过的SourceGraphic这个关键字,使内容可见。既然我们使用了alpha通道,它不仅会是透明的,且背景也必须是透明的,这点需要特别注意。

下面是基础代码:

<filter id="goo">
  <feGaussianBlur in="SourceGraphic" stdDeviation="10" result="blur" />
  <feColorMatrix in="blur" mode="matrix" values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 18 -7" result="goo" />
  <feBlend in="SourceGraphic" in2="goo" />
</filter>

代码很短,让我们分解一下:

  1. 首先,我们应用了10px的模糊到对象的原始图像上,并给输入结果取了名字;
  2. 然后,为了增加alpha通道的对比度,我们应用了一个颜色矩阵滤镜到上一步的输出结果上;
  3. 最后,在我们画出来的效果上再添加一个原始图像。

关于颜色矩阵

如果你之前没有使用过颜色矩阵滤镜,那么这里需要简单解释一下。你可以把它当成一个有4行5列的一个表格,看起来像这样:

每一行代表一个通道(red红色、green绿色、blue蓝色和alpha透明),用来设置通道的值。前面四列中的每一列也代表一个通道,并且返回它们各自通道的当前值。然后,单元格中的数字乘以由其列表示的通道的当前值的结果添加到其行通道。例如,对于每个像素点的色值,R行G列的0.5将向R通道添加原G值*0.5。最后一列不代表任何通道,只用于加/减,意味着一个数字将乘以255添加到其通道值中。

(这里好像没有解释得很清楚,自行补充一张公式图)

这是一个冗长的解释,但是使用过滤器非常简单。在我们的案例中,我们只需要提高alpha通道的对比度,颜色矩阵滤镜如下:

这样的话,RBG通道都没有改变,将alpha通道的值乘以18,然后减去7*255,就能有效地增加透明度的对比度。这些值可以根据你的需求进行调整。

要将这个矩阵应用到feColorMatrix滤镜中,我们只需要按顺序写好这些数字,如下所示:

DEMO

到这里我们的所有基础步骤就准备就绪了。

你可以根据你的需求定制它,例如添加一个阴影或者给不同的元素使用不同的颜色等等。

注意事项

  1. 滤镜需要应用在元素的包裹层上,而不是元素本身;
  2. 包裹层(容器)需要有一定的溢出区域,比如需要比它的内容区域大一些,不然你会看到边缘的锯齿;

  1. 为了能将滤镜应用于像正方形这样的尖锐图形,我们需要采取稍微复杂一点的方法。这次不像之前那样画一个原始的图形盖在胶粘效果上,我们把feComposite滤镜基元的operator属性定义为atop去遮掉除了胶粘效果之外的东西。

这样的话,滤镜就不单单能应用到复杂的胶粘效果中,也可以实现多个长方形组合起来的圆角之类的较为简单的效果。

  1. SVG滤镜虽然本身不大,但是非常消耗资源,因此要避免大面积地使用。

兼容性

SVG滤镜的兼容性良好,但不是所有的浏览器都支持它们应用到常规的DOM元素上,特别是Safari。但是它们至少可以在Firefox和Chrome上正常运行,即使在安卓版本中,如果不能正常运行也会完美降级。如果你确实需要在工作中运用这个效果,可以考虑使用SVG元素替代DOM元素。

评论 抢沙发

表情