粘性效果

Avatar of Lucas Bebber
Lucas Bebber

DigitalOcean 为您旅程的每个阶段提供云产品。 立即开始使用 200 美元的免费信用额度!

以下是 Lucas Bebber 的文章。 Lucas 是我在网络上见过的最具创意效果的创造者之一。 如此之多,以至于我无法抗拒 自己写一篇关于它们的博客文章 好几次。 这次好多了:我们请来了这位大师来解释 SVG 过滤器的运作原理以及如何使用它们来创建一个非常酷的粘性效果。

不久前,Chris 写了关于 CSS 中的形状粘合。 这个效果很酷,背后的技术也很巧妙,但是这种方法(通过普通的 CSS 过滤器)有几个缺点:没有透明度,粘合内部没有内容,很难做出除黑白以外的颜色,等等。

然而,这些天,我在玩弄 SVG 过滤器时,我发现可以使用它们来解决纯 CSS 方法的大多数问题。 在这里,您可以看到我制作的一个粘性菜单来演示这种效果。

查看 Pen CSS 粘性菜单(版本 1) by Lucas Bebber (@lbebber) on CodePen.

SVG 过滤器 101

SVG 过滤器非常强大。 这是一个相当广泛的主题。 在这里,我们只介绍理解此效果的工作原理所需的要素。

尽管有这个名字,我们仍然可以通过 CSS 将 SVG 过滤器应用于普通 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> 元素包含一个或多个过滤器原语,它们是过滤器执行的操作,例如模糊、颜色变换、阴影。 可以在 这里 找到过滤器原语的完整列表。

让我们看几个例子

查看 Pen svg 模糊演示 by Lucas Bebber (@lbebber) on CodePen.

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

此过滤器将对对象进行简单的 3 像素模糊。 注意 in="SourceGraphic" 属性。 in 属性定义了过滤器原语的输入。 SourceGraphic 是一个关键字,它返回元素的原始预过滤器图形。 因此,这意味着模糊过滤器的输入将是对象原始图形。 很简单。

现在,让我们看一个常见但更复杂的效果:投影过滤器。 这将有助于演示如何将过滤器原语链接在一起。

查看 Pen svg 投影演示 by Lucas Bebber (@lbebber) on CodePen.

<filter id="drop-shadow">
  <feGaussianBlur in="SourceGraphic" stdDeviation="7" result="shadow" />
  <feOffset in="shadow" dx="3" dy="4" result="shadow" />
  <feColorMatrix in="shadow" type="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 属性,您可以命名过滤器的结果,然后将过滤器应用于该结果而不是源图形。 这使您能够,例如,模糊一个对象,使模糊的对象变暗,然后移动模糊和变暗的对象的位置。

注意最后一个元素,<feBlend> 原语。 它表明一些过滤器原语接受多个输入(in2 参数),并且您可以在过滤器的任何位置多次调用 SourceGraphic 关键字。 例如,最后一个过滤器采用 SourceGraphic 关键字和 shadow 结果将原始图像放回我们制作的阴影之上。

现在已经介绍了 SVG 过滤器的基本知识,让我们看看如何制作粘性效果。

使物体粘在一起

基本技术已经在 这里 介绍过。 概括地说,这个想法是将两个或多个对象模糊在一起,然后增加对比度。 很简单,而且效果很好。

查看 Pen metaballs 演示 by Lucas Bebber (@lbebber) on CodePen.

但是,正如我们之前所见,这也会

  1. 弄乱颜色,使其难以做出除黑白以外的颜色。
  2. 将内容模糊在一起,使其无法使用。
  3. 容器需要背景,因此没有透明度。

总而言之,这使得这种效果通常不切实际。

然而,借助 SVG 过滤器,我们可以做一些使用 CSS 过滤器无法做到的事情:我们可以只增加 alpha 通道的对比度,而不改变颜色;并且我们可以使用之前见过的 SourceGraphic 关键字,使内容也可见。 此外,由于我们正在处理 alpha 通道,它不仅是透明的,而且透明背景是*必需的*,因此请小心。

因此,这是基本代码

<filter id="goo">
  <feGaussianBlur in="SourceGraphic" stdDeviation="10" result="blur" />
  <feColorMatrix in="blur" type="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. 首先,我们将 SourceGraphic 模糊 10 像素,并为该结果命名。
  2. 然后,对之前的结果,我们应用了一个颜色矩阵过滤器以增加 alpha 通道的对比度。
  3. 最后,我们将原始图形插入到我们制作的效果之上。

关于颜色矩阵

如果您之前没有使用过颜色矩阵过滤器,可能需要一些解释。 可以将其视为一个四行五列的表格。 它看起来像这样

   | R | G | B | A | +
---|-------------------
 R | 1 | 0 | 0 | 0 | 0
---|-------------------
 G | 0 | 1 | 0 | 0 | 0
---|-------------------
 B | 0 | 0 | 1 | 0 | 0
---|-------------------
 A | 0 | 0 | 0 | 1 | 0
---|-------------------

每行代表一个通道(红色、绿色、蓝色和 alpha),用于设置通道的值。 前四列中的每一列都代表一个通道,它们返回其各自通道的当前值。 然后,单元格中的数字会向其行通道添加该数字乘以其列表示的通道的当前值的乘积的结果。 例如,R 行、G 列上的 0.5 会为每个像素的红色通道添加绿色*0.5 的当前值。 最后一列不代表任何通道,用于加减,这意味着那里的数字会向其通道添加其值乘以 255 的结果。

这是一个冗长的解释,但使用过滤器非常简单。 在我们的例子中,由于我们只增加了 alpha 通道的对比度,因此我们的矩阵将如下所示

   | R | G | B | A | +
---|-------------------
 R | 1 | 0 | 0 | 0 | 0
---|-------------------
 G | 0 | 1 | 0 | 0 | 0
---|-------------------
 B | 0 | 0 | 1 | 0 | 0
---|-------------------
 A | 0 | 0 | 0 |18 |-7
---|-------------------

这不会修改 RGB 通道,会将 alpha 通道的值乘以 18,然后从该值中减去 7*255,从而有效地仅增加透明度的对比度。 这些值可以根据您的需要进行调整。

要将此矩阵应用于我们的 feColorMatrix 过滤器,我们只需按顺序写下这些数字,如下所示

values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 18 -7"

演示

有了这些,我们就可以创建基本效果了! 这里就是它

查看 Pen svg 粘性效果演示 by Lucas Bebber (@lbebber) on CodePen.

然后,您可以根据需要对其进行自定义,例如添加投影、为每个元素使用不同的颜色,或者任何您想要的东西!

注意事项

  • 过滤器应该应用于元素的*容器*,而不是元素本身。
  • 容器应该有一些出血区域,即它应该比其内容大一点,否则您可能会在边缘看到伪影。
    边缘的伪影
  • 为了能够将此过滤器应用于矩形等尖锐物体,我们必须采用更复杂的方法。 而不是将原始图像直接绘制到粘性效果之上,我们可以使用带有 atop 运算符的 feComposite 过滤器来遮蔽粘性外部的任何内容。

    <filter id="fancy-goo">
      <feGaussianBlur in="SourceGraphic" stdDeviation="10" result="blur" />
      <feColorMatrix in="blur" type="matrix" values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 19 -9" result="goo" />
      <feComposite in="SourceGraphic" in2="goo" operator="atop"/>
    </filter>

    查看 Pen 应用粘性过滤器的两种方法的比较 by Lucas Bebber (@lbebber) on CodePen.

    这样,我们就可以使用此过滤器不仅可以制作这种花哨的粘性效果,还可以用于更简单的应用,例如,使采用多个矩形的形状的角变圆。

  • 虽然此过滤器体积小,但如果应用于大区域,可能会占用大量资源,因此请注意这一点。

支持

SVG 滤镜具有良好的支持,但并非所有浏览器都支持将其应用于常规 DOM 元素,特别是 Safari。但是,它们至少在 Firefox 和 Chrome 上运行,即使是 Android 版本,如果滤镜不起作用,也会很好地降级。如果您绝对需要效果起作用,请考虑使用 SVG 元素而不是 DOM 元素。