为什么我们需要对SVG应用阴影?
:hover
,
:focus
, 或
:active
),以向用户表示互动。
既然我们在做列表,有两种主要的方式可以将阴影应用到SVG中。
[filter()](https://css-tricks.com/almanac/properties/f/filter/)
属性
<filter>
是的,这两种方法都涉及过滤器而且,是的,CSS和SVG都有自己的过滤器类型。但是,这两者之间也有一些交叉点。例如,一个CSS
filter
可以参考一个SVG
<filter>
;也就是说,如果我们使用的是一个内联SVG,而不是在CSS中作为背景图片的SVG。
**你不能使用的是:**CSS
box-shadow
属性。这通常用于阴影,但是它遵循元素的矩形外边缘,而不是我们想要的SVG元素的边缘。下面是Michelle Barker的
清晰解释
。
如果你使用的是SVG图标字体,那么总是有一个
[text-shadow](https://css-tricks.com/almanac/properties/t/text-shadow/)
.这确实会起作用。但是,让我们把注意力放在前两个方面,因为它们符合大多数的使用情况。
使用CSS过滤器的阴影
通过CSS滤镜直接对SVG应用阴影的诀窍是
drop-shadow()
函数。
svg {
filter: drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));
这将应用一个水平方向上从3px开始,向下5px的阴影,有2px的模糊度,并且是40%的黑色。
这个浏览器支持数据来自Caniuse,它有更多细节。一个数字表示该浏览器在该版本及以上支持该功能。
桌面浏览器
<filter id='shadow' color-interpolation-filters="sRGB">
<feDropShadow dx="2" dy="2" stdDeviation="3" flood-opacity="0.5"/>
</filter>
我们可以用一个CSS过滤器来调用这个SVG过滤器的ID,而不是我们之前看到的值。
svg {
filter: url(#shadow);
现在这个过滤器被从HTML中提取出来,并在CSS中被引用,从而应用它。
使用SVG过滤器基元
你可能想知道我们是如何让那个SVG<filter>
工作的。为了用SVG滤镜制作一个阴影,我们使用了一个滤镜基元。SVG中的过滤器基元是一个元素,它接受某种图像或图形作为输入,然后在被调用时输出该图像或图形。它们的工作方式类似于图形编辑应用程序中的过滤器,但在代码中,只能在SVG [<filter>](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/filter)
元素内使用。
SVG中有很多不同的过滤基元。我们正在使用的是<feDropShadow>
。我可以让你通过看名字来猜测它的作用。
所以,类似于我们用CSS过滤器做的这样的事情。
svg {
filter: drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));
...我们可以用<feDropShadow>
SVG过滤器基元完成同样的工作。有三个关键属性值得一提,因为它们有助于定义阴影的外观。
dx
- 这将使阴影的位置沿X轴移动。
dy
- 这将使阴影的位置沿Y轴移动。
stdDeviation
- 这定义了水滴阴影的模糊操作的标准偏差。还有其他我们可以使用的属性,比如用于设置阴影颜色的 ,以及用于设置阴影不透明度的 。flood-color
flood-opacity
这个例子包括三个<filter>
,每个元素都有自己的<feDropShadow>
过滤器基元。
使用SVG过滤器
SVG过滤器是非常强大的。我们刚刚看了<feDropShadow>
,这当然是非常有用的,但是它们能做的事情太多了(包括类似Photoshop的效果),而且我们只为阴影得到的东西子集也很广泛。让我们来看看一些,比如彩色阴影和嵌入阴影。
让我们以Twitter标志的SVG标记为例。
<svg class="svg-icon" viewBox="0 0 20 20">
<path fill="#4691f6" d="M18.258,3.266c-0.693,0.405-1.46,0.698-2.277,0.857c-0.653-0.686-1.586-1.115-2.618-1.115c-1.98,0-3.586,1.581-3.586,3.53c0,0.276,0.031,0.545,0.092,0.805C6.888,7.195,4.245,5.79,2.476,3.654C2.167,4.176,1.99,4.781,1.99,5.429c0,1.224,0.633,2.305,1.596,2.938C2.999,8.349,2.445,8.19,1.961,7.925C1.96,7.94,1.96,7.954,1.96,7.97c0,1.71,1.237,3.138,2.877,3.462c-0.301,0.08-0.617,0.123-0.945,0.123c-0.23,0-0.456-0.021-0.674-0.062c0.456,1.402,1.781,2.422,3.35,2.451c-1.228,0.947-2.773,1.512-4.454,1.512c-0.291,0-0.575-0.016-0.855-0.049c1.588,1,3.473,1.586,5.498,1.586c6.598,0,10.205-5.379,10.205-10.045c0-0.153-0.003-0.305-0.01-0.456c0.7-0.499,1.308-1.12,1.789-1.827c-0.644,0.28-1.334,0.469-2.06,0.555C17.422,4.782,17.99,4.091,18.258,3.266" ></path>
我们将需要一个<filter>
元素来做这些效果。这需要在HTML中的一个<svg>
元素内。一个<filter>
元素永远不会在浏览器中直接呈现--它只被用作可以通过SVG中的filter
属性或CSS中的url()
函数来引用的东西。
下面是显示SVG过滤器并将其应用于源图像的语法。
<svg width="300" height="300" viewBox="0 0 300 300">
<filter id="myfilters">
<!-- All filter effects/primitives go in here -->
</filter>
<g filter="url(#myfilters)">
<!-- Filter applies to everything in this group -->
<path fill="..." d="..." ></path>
</svg>
filter
元素是用来容纳作为子元素的过滤器基元的。它是一系列过滤操作的容器,这些过滤操作被组合起来形成一个过滤效果。
这些滤镜基元在一个或多个输入上执行单一的基本图形操作(例如,模糊、移动、填充、组合或扭曲)。它们就像积木一样,每个SVG滤镜都可以与其他滤镜结合起来使用,从而创造出一种效果。<feGaussianBlur>
是一个常用的滤镜基元,用于添加模糊效果。
假设我们用<feGaussianBlur>
来定义下面这个SVG过滤器。
<svg version="1.1" width="0" height="0">
<filter id="gaussian-blur">
<feGaussianBlur stdDeviation="1 0" />
</filter>
当应用于一个元素时,这个过滤器会创建一个高斯模糊,在X轴上以1px
为半径模糊元素,但在Y轴上没有模糊。
在一个单一的过滤器内使用多个基元是可能的。这将创造出有趣的效果,然而,你需要让不同的基元相互认识。Bence Szabó有一套疯狂酷炫的图案,他就是这样创建的。
组合多个滤波器基元时,第一个基元使用原始图形 (SourceGraphic
) 作为其图形输入。任何后续的基元都使用它之前的滤波器效果的结果作为其输入。以此类推。但是,我们可以通过使用基元元素上的in
、in2
和result
属性获得一些灵活性。史蒂文-布拉德利(Steven Bradley)有一篇关于过滤器基元的优秀文章,可以追溯到2016年,但今天仍然适用。
今天我们有17个基元可以使用。
<feGaussianBlur>
<feDropShadow>
<feMorphology>
<feDisplacementMap>
<feBlend>
<feColorMatrix>
<feConvolveMatrix>
<feComponentTransfer>
<feSpecularLighting>
<feDiffuseLighting>
<feFlood>
<feTurbulence>
<feImage>
<feTile>
<feOffset>
<feComposite>
<feMerge>
注意所有这些基元上的fe
前缀。这代表的是滤镜效果。理解SVG滤镜是一项挑战。像插入式阴影这样的效果需要一个冗长的语法,如果没有对数学和色彩理论的透彻理解,就很难掌握。(Rob O'Leary的"深入了解阴影 "是一个很好的开始。)
与其跑到这些东西的兔子洞里,我们不如用一些预制的过滤器来工作。幸运的是,周围有很多现成的SVG过滤器。
为了在Twitter标志上使用滤镜效果,我们需要在我们的 "SVG源文件 "中声明它的唯一ID,以便在我们的<filter>
标签中进行引用。
<filter id='inset-shadow'>
<!-- Shadow offset -->
<feOffset
dx='0'
dy='0'
<!-- Shadow blur -->
<feGaussianBlur
stdDeviation='1'
result='offset-blur'
<!-- Invert drop shadow to make an inset shadow -->
<feComposite
operator='out'
in='SourceGraphic'
in2='offset-blur'
result='inverse'
<!-- Cut color inside shadow -->
<feFlood
flood-color='black'
flood-opacity='.95'
result='color'
<feComposite
operator='in'
in='color'
in2='inverse'
result='shadow'
<!-- Placing shadow over element -->
<feComposite
operator='over'
in='shadow'
in2='SourceGraphic'
</filter>
这里面有四个不同的基元,每一个都执行不同的功能。但是,合在一起,它们实现了一个嵌入阴影。
现在我们已经创建了这个嵌入阴影过滤器,我们可以把它应用到我们的SVG中。我们已经看到了如何通过CSS来应用它。比如说。
.filtered {
filter: url(#myfilters);
/* Or apply only in certain states, like: */
svg:hover, svg:focus {
filter: url(#myfilters);
我们也可以在SVG语法中直接使用filter
属性来应用SVG<filter>
。这就像
<!-- Apply a single filter -->
<path d="..." filter="url(#myfilters)" />
<!-- Or apply to a whole group of elements -->
<g filter="url(#myfilters)">
<path d="..." />
<path d="..." />
</svg>
最后做个比较。
CSS过滤器更容易使用,但局限性也更大。例如,我认为不可能用drop-shadow()
函数来添加一个嵌入的阴影。
SVG过滤器要强大得多,但也要复杂得多,而且需要在HTML中的某个地方设置<filter>
。
它们都有很好的浏览器支持,在所有的现代浏览器上都有很好的表现,尽管SVG过滤器(令人惊讶地)有最深的浏览器支持。
在这篇文章中,我们已经看到了为什么以及如何在SVG图标上应用阴影,并分别举了例子。你是否也做过这样的事情,但做的方式与我们看的都不一样?你是否尝试过做一个阴影效果,但你发现不可能完成?请分享吧