SVG过滤效果。 第1部分。SVG过滤器101

拟议的系列文章“ SVG过滤效果 ”,作者:Sara Soueidan,是自由UI / UX界面开发人员,并且是黎巴嫩的许多技术文章的作者,重点关注SVG过滤器的工作,并包括以下文章:


SVG过滤效果


  1. SVG滤镜的效果。 第1部分。SVG过滤器101。
  2. SVG滤镜的效果。 第2部分。使用特征形态轮廓文本
  3. SVG过滤效果。 第3部分。使用feComponentTransfer进行图像后代化的效果
  4. SVG过滤效果。 第4部分feComponentTransfer的两色图像
  5. SVG过滤效果。 第5部分。使用feDisplacementMap将文本与表面纹理匹配



这是有关SVG过滤器系列的第一篇文章。 本指南将帮助您了解其含义,并向您展示如何使用它们创建自己的视觉效果。



CSS当前为我们提供了一种方法,可以使用滤镜属性及其随附的功能将色彩效果(例如饱和度,亮度和对比度)以及其他效果应用于图像。


现在,我们在CSS中有11个过滤器函数,它们执行从模糊到改变颜色对比度和饱和度的许多效果,以及更多功能。 有关更多信息, 请参阅CSS参考


尽管功能强大且非常方便,但是CSS过滤器也非常有限。 我们可以用它们创建的效果通常适用于图像,并且仅限于颜色处理和简单的模糊处理。 因此,要创建可以应用于更广泛元素的更强大的效果,我们需要更广泛的功能。 这些功能今天可用,并且在SVG中已经使用了十多年。 在SVG过滤器系列的第一篇文章中,您将了解SVG过滤器的功能(称为“原语”)以及如何使用它们。


CSS过滤器是从SVG导入的。 它们是SVG中引入的滤镜效果子集的相当优化的版本,并且已经存在于SVG规范中很多年了。


SVG比CSS具有更多的过滤效果,并且SVG版本比CSS快捷方式功能更强大且执行的效果更复杂。 例如,您当前可以使用blur() CSS过滤器功能对元素进行模糊处理 。 通过此功能应用模糊效果将为要应用该模糊效果的元素创建均匀的高斯模糊。 下图显示了将6px模糊应用于CSS中的图像的结果:


应用**模糊()函数的效果-高斯模糊
图_1。 应用blur() CSS函数的效果是高斯模糊。


blur()函数创建一种模糊效果,该效果均匀地应用在图像的两个方向(X和Y)上。 但是,此功能只是对SVG中可用的模糊滤镜基元的简化和有限的减少,它使我们能够均匀地模糊图像或沿X轴或Y轴应用单向模糊效果。


分别沿轴应用SVG函数**模糊()**的效果
图_2。 分别沿轴应用blur() SVG函数的效果。


SVG过滤器可以应用于HTML元素和SVG元素。 可以使用url()过滤器功能将SVG过滤效果应用于CSS中的HTML元素。 例如,如果您具有在SVG中定义的标识符myAwesomeEffect的滤镜效果(我们将在不久的将来讨论在SVG中定义滤镜效果),则可以将此效果应用于HTML元素或图像,如下所示:


.el { filter: url(#myAwesomeEffect); } 

最好的是,正如您在本系列文章中将看到的那样,SVG滤镜能够使用几行代码在浏览器中创建Photoshop级别的效果。 我希望本系列文章将有助于消除秘密的光环,并释放SVG过滤器潜力的一部分,这将启发您在自己的项目中使用它们。


但是,您对浏览器的支持又如何呢?


浏览器支持


浏览器对大多数SVG过滤器的支持令人印象深刻。 但是,在某些浏览器中,应用效果的方法可能有所不同,这取决于它们对SVG过滤效果中使用的各个过滤器原语的支持以及可能的浏览器错误。 将SVG过滤器应用于SVG元素或HTML元素时,浏览器支持也可能会有所不同。


我建议您将过滤效果视为一种扩展:几乎可以始终在不使用过滤器的完全有用的体验之上应用效果作为改进。 许多人知道,我支持在可能的情况下逐步创建UI的方法。 因此,在本系列文章中,我们不必过多担心浏览器的支持。


最后,尽管通常对SVG滤波器的支持不错,但请记住,我们稍后将讨论的某些效果可以视为实验性的。 如果有的话,我会指出任何重大问题或错误。


那么,如何在SVG中定义和创建过滤效果?


<Filter>元素


像SVG中的线性渐变,蒙版,图案和其他图形效果一样,滤镜具有一个方便命名的特殊元素: <filter>


它从不直接显示,而仅用作可通过SVG中的filter属性或CSS中的url()函数引用的对象。 在没有显式引用的情况下无法显示的元素通常被定义为SVG中<defs>元素内的模板。 但是SVG <filter>不需要包装在defs元素中。 无论您是否将过滤器包装在defs元素中,它都不会显示。


原因是滤镜需要处理原始图像 。 而且,如果您没有通过在其上调用过滤器来明确定义此源图像,则该过滤器将无法呈现任何内容,因此将无法使用。


一个非常简单,最少的代码示例,它定义了SVG过滤器并将其应用于SVG中的原始图像,如下所示:


 <svg width="600" height="450" viewBox="0 0 600 450"> <filter id="myFilter"> <!-- filter effects go in here --> </filter> <image xlink:href="..." width="100%" height="100%" x="0" y="0" filter="url(#myFilter)"></image> </svg> 

上面的代码示例中的过滤器目前为空,因为它为空。 要创建滤镜效果,必须定义一系列在滤镜内部创建此效果的一个或多个滤镜操作。 换句话说, <filter>元素是一系列过滤操作的容器,这些操作共同创建过滤效果。 SVG中的这些过滤操作称为“ 过滤器原语 ”。


过滤原语


因此,在SVG中,每个<filter>元素都包含一组过滤器原语作为子元素。 每个过滤器原语在一个或几个输入上执行一个基本的图形运算,从而创建图形结果。


过滤器基元以它们执行的图形操作方便地命名。 例如,将高斯模糊效果应用于图形源的图元称为feGaussianBlur 。 所有基元都有相同的前缀:fe,“ filter effect ”的缩写。 同样,SVG中的名称便于选择以了解此元素的含义或作用。


以下代码段显示了对图像应用5px高斯模糊时简单滤镜的外观:


 <svg width="600" height="450" viewBox="0 0 600 450"> <filter id="myFilter"> <feGaussianBlur stDeviation="5"></feGaussianBlur> </filter> <image xlink:href="..." width="100%" height="100%" x="0" y="0" filter="url(#myFilter)"></image> </svg> 

当前, SVG滤镜规范定义了17种滤镜原语,它们能够创建极其强大的图形效果,包括但不限于噪声和纹理生成,照明效果,颜色操纵(通道间)等等。


过滤器原语通过接受图形源进行输入和输出到另一个来工作。 一个滤镜效果的输出可用作另一个滤镜效果的输入。 这非常重要且非常有效,因为使用几乎无数种滤镜效果组合,您可以创建几乎无数种图形效果。


每个过滤器原语只能接受一个或两个输入,而只能输出一个结果。 过滤器原语的输入在in属性中定义。 操作的结果result属性中定义。 如果滤镜效果需要第二个输入,则在in2属性中指定它。 该操作的结果可以用作任何其他操作的输入,但是如果未在in属性中指定该操作的输入,则前一个操作的结果将自动用作输入。 如果您未指定原语的结果 ,则其结果将自动用作下一个原语的输入。 当我们开始研究代码示例时,这一点将变得更加清楚。


过滤器原语可以使用其他数据类型作为输入,其中最重要的是:


  • SourceGraphic :整个过滤器应用于的元素; 例如,图像或一段文字。
  • SourceAlpha :与SourceGraphic相同,除了此图形仅包含元素的alpha通道。 例如,对于JPEG图像,这是一个黑色矩形,其大小等于图像本身的大小。

您会发现有时需要将图形源用作输入,有时仅将其Alpha通道用作输入。 我们将在本文及后续文章中介绍的示例将使您清楚地了解何时以及使用什么方式。


此代码段是一个过滤器的外观示例,其中一个过滤器基元数据包作为子级。 不要担心基元及其作用。 此时,只需注意如何定义和使用某些原语的输入和输出。 我添加了一些评论以寻求帮助。


 <svg width="600" height="400" viewBox="0 0 850 650"> <filter id="filter"> <feOffset in="SourceAlpha" dx="20" dy="20"></feOffset> <!-- since the previous filter did not have a result defined and this following one does not have the input set, the result of the above primitive is automatically used as input to the following filter --> <feGaussianBlur stdDeviation="10" result="DROP"></feGaussianBlur> <!-- setting/defining the result names in all caps is a good way to make them more distinguishable and the overall code more readable --> <feFlood flood-color="#000" result="COLOR"></feFlood> <!-- This primitive is using the outputs of the previous two primitives as input, and outputting a new effect --> <feComposite in="DROP" in2="COLOR" operator="in" result="SHADOW1"></feComposite> <feComponentTransfer in="SHADOW1" result="SHADOW"> <feFuncA type="table" tableValues="0 0.5"></feFuncA> </feComponentTransfer> <!-- You can use ANY two results as inputs to any primitive, regardless of their order in the DOM.--> <feMerge> <feMergeNode in="SHADOW"></feMergeNode> <feMergeNode in="SourceGraphic"></feMergeNode> </feMerge> </filter> <image xlink:href="..." x="0" y="0" width="100%" height="100%" filter="url(#filter)"></image> </svg> 

现在,在继续我们的第一个过滤器示例之前,我要简要解释的最后一个概念是Filter Region的概念。


过滤面积


一组过滤操作需要一个要处理的区域,一个可以对其应用的区域。 例如,您可能有一个包含许多元素的复杂SVG,并且您只想将过滤效果应用于特定区域或同一SVG中的一个或一组元素。


在SVG中,元素具有“区域”,其边界由界定元素的矩形边缘定义。 边界框(也称为“ bbox”)是元素周围最小的封闭矩形。 例如,在下图中,对于一段文本,此类矩形用粉红色突出显示。


一段文字周围的最小封闭矩形
图_3。 一段文字周围最小的封闭矩形。


请注意,此矩形可能包含更多垂直空间,因为在计算边界矩形的高度时会考虑文本行的高度。


默认情况下,元素过滤器区域是边界元素框架。 因此,如果您对文本片段应用滤镜效果,则该效果将仅限于此矩形,并且超出该矩形的任何滤镜结果都将被切除。 尽管这是合理的,但它不是很实用,因为许多滤镜会影响边界框外的某些像素,默认情况下,这些像素最终会被切除。


例如,如果您对文本片段应用模糊效果,则可以看到它是沿着界定文本的矩形的左右边缘裁剪的:


缩进的文本的模糊效果会在界定文本的矩形的左右两边都进行缩小。
图_4。 应用于文本的模糊效果会在界定文本的矩形的左右两侧都进行裁剪。


那么我们如何防止这种情况呢? 答案是:通过扩大过滤面积。 我们可以通过更改<filter>元素的xywidthheight属性来扩展应用过滤器的范围。


根据规范,


通常,必须在滤镜区域中提供字段,因为滤镜效果可能会影响给定对象的边界框外的某些位。 为此,您可以为XY属性提供负值(以百分比表示),为widthheight属性提供大于100%的值。

默认情况下,过滤器的区域在所有四个方向上都延伸出边框的宽度和高度的10%。 换句话说, xywidthheight属性的默认值为:


 <filter x="-10%" y="-10%" width="120%" height="120%" filterUnits="objectBoundingBox"> <!-- filter operations here --> </filter> 

如果您未在<filter>元素中包括这些属性,则将使用默认值。 您也可以根据需要覆盖它们以扩大或缩小面积。


请记住,在xywidthheight属性中使用的单位取决于所使用的filterUnits属性 。 它定义了属性xywidthheight的坐标系,并且可以采用以下两个值之一:


  • objectBoundingBox 。 这是默认值。 当filterUnits设置为objectBoundingBox时xywidthheight属性值是元素边界框大小的百分比或分数。 这也意味着您可以根据需要使用分数值而不是百分比。
  • userSpaceOnUse如果将filterUnits设置为userSpaceOnUse ,则x,y,width和height属性的坐标相对于用户使用的当前坐标系。 换句话说,这与SVG中使用的当前坐标系有关,后者使用像素作为度量单位,并且通常相对于SVG本身的大小,假设viewBox值对应于原始坐标系的值。

您需要了解的有关SVG中坐标系统的所有信息都可以在我几年前写的这篇文章中找到。

 <!-- Using objectBoundingBox units --> <filter id="filter" x="5%" y="5%" width="100%" height="100%"> <!-- Using userSpaceOnUse units --> <filter id="filter" filterUnits="userSpaceOnUse" x="5px" y="5px" width="500px" height="350px"> 

快速提示:使用feFlood可视化当前过滤器区域


如果您需要查看滤镜区域的界限,可以通过用某种颜色填充滤镜来使其可视化。 方便地,有一个名为feFlood的过滤器原语,其唯一目的就是这样做:用Flood-Color属性中指定的颜色填充当前过滤器区域。


因此,如果我们假设有一段文本,我们希望看到其过滤区域,那么代码可能看起来像这样:


 <svg width="600px" height="400px" viewBox="0 0 600 400"> <filter id="flooder" x="0" y="0" width="100%" height="100%"> <feFlood flood-color="#EB0066" flood-opacity=".9"></feFlood> </filter> <text dx="100" dy="200" font-size="150" font-weight="bold" filter="url(#flooder)">Effect!</text> </svg> 

从上面的代码片段中可以看到, feFlood原语也接受Flood-opacity属性,该属性可用于创建填充颜色层的透明度。


上面的代码段用粉红色填充了过滤器区域。 事情是这样的:当您用颜色填充区域时,实际上是用颜色填充它,这意味着颜色将覆盖滤镜区域中的所有内容,包括您先前创建的任何元素和效果以及文本本身。 毕竟,这就是填充的概念,对吗?


用颜色填充过滤器文本区域之前和之后
图_5。 在用颜色填充过滤器的文本区域之前和之后。


要更改此设置,我们需要将颜色层移到下面,并在顶部显示原始文本层。


如果在SVG过滤器中有多个应在彼此之上显示的上下文层,则可以使用<feMerge>过滤器原语。 顾名思义, feMerge原语用于将元素或效果层组合在一起。


该原语没有in属性。 为了合并<feMerge>内部的层,使用了两个或多个<feMergeNode> ,每个层中都有自己的属性,表示我们要添加的层。

层(或“节点”)的放置取决于源<feMergeNode>的顺序-第一个<feMergeNode>显示在第二个“后面”或“下面”。 最后一个<feMergeNode>代表最顶层。 依此类推。


因此,在带有文本的示例中,颜色填充是一个图层,文本源(图形源)是一个不同的图层,我们希望将文本放在颜色填充的顶部。 我们的代码如下所示:


 <svg width="600px" height="400px" viewBox="0 0 600 400"> <filter id="flooder"> <feFlood flood-color="#EB0066" flood-opacity=".9" result="FLOOD"></feFlood> <feMerge> <feMergeNode in="FLOOD" /> <feMergeNode in="SourceGraphic" /> </feMerge> </filter> <text dx="100" dy="200" font-size="150" font-weight="bold" filter="url(#flooder)">Effect!</text> </svg> 

请注意,我是如何result属性中命名feFlood结果的 ,以便可以在<feMergeNode>层中将此名称用作输入。 由于我们想在流颜色的顶部显示源文本,因此我们使用SourceGraphic引用此文本。 以下演示显示了结果:



对图像应用阴影


让我以一个简短的警告开始:最好使用drop-shadow() CSS过滤功能创建一个简单的阴影。 SVG过滤器路径更为冗长。 毕竟,正如我们前面提到的,CSS过滤器功能是便捷的快捷方式。 但是我仍然想将此示例视为更复杂的滤镜效果的简单切入点,我们将在以后的文章中介绍。


那么阴影是如何产生的呢?


阴影通常是元素后方或下方的浅灰色层,其形状与元素本身相同。 换句话说,您可以将其视为元素的模糊灰色副本。


创建SVG过滤器时,您需要分阶段进行推理。 要实现此效果,必须采取什么步骤? 对于阴影,可以通过模糊元素的黑色副本然后为该黑色副本上色(即着色)来创建元素的灰色副本。 使她变灰。 然后,将此新创建的模糊灰色副本放置在原始元素的后面,并在两个方向上稍有偏移。


因此,我们将从获取元素的黑色副本并将其模糊化开始 。 可以使用元素的Alpha通道(使用SourceAlpha作为过滤器输入)创建黑色副本。


feGaussianBlur原语将用于将高斯模糊应用于此SourceAlpha层。 所需的模糊量在stdDeviation属性中设置(“标准偏差”的缩写)。 如果设置stdDeviation属性的一个值,则该值将用于对输入数据进行均匀模糊处理。 您还可以指定两个数值,然后第一个将用于在水平方向上模糊元素,第二个将用于垂直模糊。 对于阴影,我们需要应用均匀的模糊,因此我们的代码将从以下内容开始:


 <svg width="600" height="400" viewBox="0 0 850 650"> <filter id="drop-shadow"> <-- Grab a blakc copy of the source image and blur it by 10 --> <feGaussianBlur in="SourceAlpha" stdDeviation="10" result="DROP"></feGaussianBlur> </filter> <image xlink:href="..." x="0" y="0" width="100%" height="100%" filter="url(#drop-shadow)"></image> </svg> 

上面的代码段具有以下效果,其中当前仅显示图像的模糊Alpha通道:


创建具有模糊(阴影)的黑色复制图像
图_6。 创建具有模糊(阴影)图像的黑色副本。


然后我们要更改阴影的颜色并将其变为灰色 。 为此,我们将颜色填充应用于滤镜区域,然后将该颜色填充层与我们创建的阴影层组合在一起。


对齐是图形元素与模糊背景的连接。 模糊的背景是与元素对齐的元素后面的内容。 在我们的滤镜中,填充色是顶层,而模糊的阴影是背景,因为它位于它的后面。 在以下文章中,我们将更详细地考虑feComposite原语,因此,如果您不熟悉该组合及其工作方式,那么建议您在我的博客中阅读有关此主题的详细文章


feComposite原语具有一个operator属性,该属性用于指示我们要使用的复合操作。


使用in复合运算符,颜色填充层将被“剪切”,并且仅显示与阴影层匹配的颜色区域。 这两层将在它们相交的地方混合在一起,即 灰色将用于为黑色阴影着色。


feComposite , in in2 . — , — . , operator , :


 <svg width="600" height="400" viewBox="0 0 850 650"> <filter id="drop-shadow"> <feGaussianBlur in="SourceAlpha" stdDeviation="10" result="DROP"></feGaussianBlur> <feFlood flood-color="#bbb" result="COLOR"></feFlood> <feComposite in="COLOR" in2="DROP" operator="in" result="SHADOW"></feComposite> </filter> <image xlink:href="..." x="0" y="0" width="100%" height="100%" filter="url(#drop-shadow)"></image> </svg> 

, feGaussianBlur feFlood . :


现在阴影是灰色的
_7. .


, , / . . , , , .


SVG feOffset . in result : dx dy , , X Y .


, , feMerge , , — mergeNode , mergeNode , SourceGraphic . :


 <svg width="600" height="400" viewBox="0 0 850 650"> <filter id="drop-shadow"> <!-- Get the source alpha and blur it; we'll name the result "DROP" --> <feGaussianBlur in="SourceAlpha" stdDeviation="10" result="DROP"></feGaussianBlur> <!-- flood the region with a ligh grey color; we'll name this layer "COLOR" --> <feFlood flood-color="#bbb" result="COLOR"></feFlood> <!-- Composite the DROP and COLOR layers together to colorize the shadow. The result is named "SHADOW" --> <feComposite in="COLOR" in2="DROP" operator="in" result="SHADOW"></feComposite> <!-- Move the SHADOW layer 20 pixels down and to the right. The new layer is now called "DROPSHADOW" --> <feOffset in="SHADOW" dx="20" dy="20" result="DROPSHADOW"></feOffset> <!-- Layer the DROPSHADOW and the Source Image, ensuring the image is positioned on top (remember: MergeNode order matters) --> <feMerge> <feMergeNode in="DROPSHADOW"></feMergeNode> <feMergeNode in="SourceGraphic"></feMergeNode> </feMerge> </filter> <!-- Apply the filter to the source image in the `filter` attribute --> <image xlink:href="..." x="0" y="0" width="100%" height="100%" filter="url(#drop-shadow)"></image> </svg> 

:



SVG, SVG. , .



, . , , , , , , .


, , feFlood , , , , . , . , , , , - , , , .


feColorMatrix , feComponentTransfer . feComponentTransfer , feColorMatrix , .


feColorMatrix . Una Kravet , .


, R(), G(), B() A() -. , . :


 <filter id="myFilter"> <feColorMatrix type="matrix" values="R 0 0 0 0 0 G 0 0 0 0 0 B 0 0 0 0 0 A 0 "/> </feColorMatrix> </filter> 

, .


, , RGB, - :


 <filter id="filter"> <!-- Get the source alpha and blur it, --> <feGaussianBlur in="SourceAlpha" stdDeviation="10" result="DROP"></feGaussianBlur> <!-- offset the drop shadow --> <feOffset in="SHADOW" dx="20" dy="20" result="DROPSHADOW"></feOffset> <!-- make the shadow translucent by reducing the alpha channel value to 0.3 --> <feColorMatrix type="matrix" in="DROPSHADOW" result="FINALSHADOW" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0.3 0"> </feColorMatrix> <!-- Merge the shadow and the source image --> <feMerge> <feMergeNode in="FINALHADOW"></feMergeNode> <feMergeNode in="SourceGraphic"></feMergeNode> </feMerge> </filter> 

:



结论


. , . , . , , , , , . , . , , , . .


, SVG- , . 和我们在一起。

Source: https://habr.com/ru/post/zh-CN439282/


All Articles