vector-effect
是SVG
中十分冷门的属性,相信大多数小伙伴都没有了解过,说句实话,在这次重学SVG
之前,这个属性我连听都没听说过。
不过,冷门不重要,重要的是管用,尤其是以后在面对相应场景下,能够快速的想到还有这么个属性提供了一种解决方案就足矣啦。
OK,老规矩,先来扒一扒这个属性的定义。
vector-effect的定义
MDN
vector-effect
: 属性指明绘制对象时要使用的矢量效果。在任何其他合成操作(如滤镜,蒙版和剪辑等)之前,都要应用矢量效果。该属性可以直接在CSS
样式表中使用。
作为显示性属性,它能被应用到任何元素,但只对以下元素有效果:<circle>
、 <ellipse>
、 <foreignObject>
、 <image>
、 <line>
、 <path>
、<polygon>
、 <polyline>
、 <rect>
、 <text>
、 <textPath>
和 <tspan>
。
总结一下,vector-effect
可以指定绘制对象使用的矢量效果,但是只对上述的元素生效,与大多数SVG
属性一样,可以在CSS
中直接声明。
但是矢量效果又是什么呢?那就要轮到vector-effect
的可选值出场了。
vector-effect的可选值
vector-effect
可选值有:none(默认)
| non-scaling-stroke
| non-scaling-size
| non-rotation
| fixed-position
有点多,不怕,让我们来分而食之。
作为默认值的none
none
: 该值指定不应用矢量效果,是默认的渲染行为,即首先用指定的绘画填充几何形状,然后使用指定的绘画来描边轮廓。
作为默认值,none
的表现也就是我们没指定vector-effect
时的效果,所以也是最常见的,毕竟这么冷门的属性谁会没事去指定一下呢?
.icon {width: 50px; height: 50px;stroke-width: 2px;stroke: #2486ff;fill: none;
}
.scale {width: 100px; height: 100px;
}
<svg style="display:none;"><symbol id="icon" viewBox="0 0 50 50"><circle cx="25" cy="25" r="20"/><path d="M25 15 L 25 35"/><path d="M15 25 L 35 25"/></symbol></svg>
<div class="wrapper"><p><svg class="icon"><use xlink:href="#icon"></use></svg></p><p><svg class="icon scale"><use xlink:href="#icon"></use></svg></p>
</div>
可以看到,原本50px
* 50px
的无填充icon
,在vector-effect
默认为none
时,宽高被放大到100px
* 100px
后,icon
的stoke
也就是所谓的笔触,也同样被放大了。
其实,仔细想想,这是符合SVG
矢量特性的,试想一下,一个stroke-width=1
的图形,要是被放大到一个大屏上,那么stroke如果不随着图形的增大而变粗,那么在远处看过去几乎已经无法看清了。
但是,不得不说如此放大之后,在一些小屏幕上看着好突兀,那么有没有什么办法可以在SVG
缩放的时候stroke
不跟着缩放呢?
当然是有的,下面有请non-scaling-stroke
上场。
让stroke跳脱出矢量效果的non-scaling-stroke
non-scaling-stroke
: 该值修改了笔触的方式。通常,笔触涉及在当前用户坐标系中计算形状路径的笔触轮廓,并用笔触颜料(颜色或渐变)填充轮廓。该值的最终视觉效果是笔触宽度不依赖于元素的变换(包括非均匀缩放和剪切变换)和缩放级别。
定义是不是依旧看的云里雾里,没关系,一图胜千言:
.icon {width: 50px; height: 50px;stroke-width: 2px;stroke: #2486ff;fill: none;
}
.scale {width: 100px; height: 100px;
}
.plus {vector-effect: non-scaling-stroke;
}
<svg style="display:none;"><symbol id="icon-plus" viewBox="0 0 50 50"><circle class="plus" cx="25" cy="25" r="20"/><path class="plus" d="M25 15 L 25 35"/><path class="plus" d="M15 25 L 35 25"/></symbol><symbol id="icon" viewBox="0 0 50 50"><circle cx="25" cy="25" r="20"/><path d="M25 15 L 25 35"/><path d="M15 25 L 35 25"/></symbol></svg><p><svg class="icon"><use xlink:href="#icon-plus"></use></svg></p><p><svg class="icon scale"><use xlink:href="#icon-plus"></use></svg></p><p><svg class="icon scale"><use xlink:href="#icon"></use></svg></p>
结合案例推导的话一下就明朗了,vector-effect: non-scaling-stroke
就是为了解决stroke
随着尺寸的增大而变粗的属性,当对icon-plus
设置了non-scaling-stroke
之后,即使缩放了一倍的宽高,但笔触stroke
还是保持着之前的宽度,与没有设置vector-effect
的icon
形成了鲜明的对比。
值得注意的是,无论是<svg>
或者<use>
元素上设置vector-effect
都是无效的,必须直接设置给<circle>
、<path>
。
那么,到底什么时候会用到non-scaling-stroke
的特性呢?
non-scaling-stroke的应用场景
其实,我们在实际的Web
开发中用到non-scaling-stroke
的机会并不多,因为我们选择使用SVG
时,主要就是馋它自身的矢量特性,也就是说尺寸变大时我们就需要它的stroke
也相应的变粗。
但是,如果SVG
是非等比缩放时,即preserveAspectRatio="none"
, non-scaling-stroke
就变得相当实用了,例如:
<svg class="icon rect" viewBox="4 4 42 42" preserveAspectRatio="none"><rect x="5" y="5" width="40" height="40"/><path d="M25 15 L 25 35"/><path d="M15 25 L 35 25"/>
</svg>
对于有审美的前端工程师而言,上图无论如何定义都算的上“丑”了。
可以看到,由于设置为非等比缩放,stroke
的宽度受长宽比的影响,使得竖线比横线粗了太多太多,导致严重的比例失调,这时候只需要简简单单的一句vector-effect="non-scaling-stroke"
,比例失调的问题就会被立马解决。
<svg class="icon rect" viewBox="4 4 42 42" preserveAspectRatio="none"><rect x="5" y="5" width="40" height="40"
vector-effect="non-scaling-stroke"/><path d="M25 15 L 25 35" vector-effect="non-scaling-stroke"/><path d="M15 25 L 35 25" vector-effect="non-scaling-stroke"/>
</svg>
好了,掌握了none
和non-scaling-stroke
,就相当于弄懂了整个vector-effect
属性,虽然它还有另外3
个看似很厉害的可选值,但那3
个值属实是有点“不堪重用”
。
不堪重用的另外3个可选值
这里的“不堪重用”
并不是说他们不好用,而是压根用不了(这里的测试只针对Chrome
而言)。
之所以会这样,是因为 Scalable Vector Graphics (SVG) 1.1 (Second Edition)的规范中明确指出这3
个属性有可能会从SVG 2
的规范中删除,全文如下:
Values of vector-effect other than
non-scaling-stroke
andnone
are at risk of being dropped from SVG 2 due to a lack of implementations. Feedback from implementers is requested, regarding the practicality of implementing them as currently specified, during the implementation period.
大概就是说,那哥仨还是有点不靠谱,所以除了none
和 non-scaling-stroke
被豁免之外,其他属性都有可能从SVG2
的规范中被删除。
所以,Chrome
对这种有连坐风险的属性不支持也就变得情有可原了。
虽然,浏览器不支持,规范要删除,但这都不妨碍我们来一窥这哥仨的全貌。
non-scaling-size
non-scaling-size
: 该值指定元素及其后代使用的特殊用户坐标系。尽管从宿主坐标空间进行任何转换更改,该用户坐标系的比例也不会更改。但是,它没有指定抑制旋转和偏斜。同样,它也不指定用户坐标系的原点。由于此值抑制了用户坐标系的缩放,因此它还具有non-scaling-stroke
的特性。
大概就是说这个属性可以让指定元素不受坐标系缩放效果的影响。
<path id="ve" vector-effect="non-scaling-size" stroke="red" stroke-width="3" fill="none" transform="matrix(1,0,0,1,150,150)" d ="M-50,-50 L50,-50 50,-100 150,0 50,100 50,50 -50,50 -50,-50z M5 0 L0 -5 -5 0 0 5z"/>
从图上可以看出,虽然transform
通过矩阵设置了旋转和缩放效果,但是因为设置了non-scaling-size
,所以最终渲染只是进行了旋转。
non-scaling-stroke
比non-scaling-size
相比:
non-scaling-stroke
:只有stroke
描边的宽度不会被缩放,至于fill
或图形的宽高
依旧会进行缩放。
non-scaling-size
: 无论是stroke
、fill
或宽高
都不会进行缩放,也就是说缩放在non-scaling-size
面前彻底失效了,换句话说它属于non-scaling-stroke
的上位替代。
non-rotation
non-rotation
: 该值指定元素及其后代使用的特殊用户坐标系。尽管从宿主坐标空间发生任何变换更改,该用户坐标系的旋转和倾斜仍被抑制。但是,它没有指定抑制缩放。同样,它也没有指定用户坐标系的原点。
有了上面缩放的案例,这里就要好理解多了,顾名思义不旋转
。
<path id="ve" vector-effect="non-rotation" stroke="red" stroke-width="3" fill="none" transform="matrix(1,0,0,1,150,150)" d=" M-50,-50 L50,-50 50,-100 150,0 50,100 50,50 -50,50 -50,-50z M5 0 L0 -5 -5 0 0 5z"/>
可以看到,坐标系进行了旋转和放大,但是最终渲染时图形只有放大的效果,旋转效果被non-rotation
干掉了。
fixed-position
fixed-position
: 该值指定元素及其后代使用的特殊用户坐标系。尽管从宿主坐标空间进行任何转换更改,用户坐标系的位置都是固定的。但是,它没有指定抑制旋转,偏斜和缩放。当同时指定了该矢量效果和transform
属性,transform
属性将因该矢量效果而被消耗。
看属性名称猜作用,无非就是元素的位置固定,不受transform
的效果影响。
可以看到,虽然坐标系被缩放和旋转了,但是箭头图案中的锚点位置是固定的并没有随着坐标系的改变而改变。
vector-effect的属性组合使用
与其他属性不同vector-effect
是可以组合使用的,只不过目前只有none
和 non-scaling-stroke
可用,况且这两货还互相冲突的属性,所以组合的意义不大,但是换成以上那哥仨效果一下就有趣了起来。
试想一下,哥仨同时生效之后,就代表着指定元素不受任何转换旋转
、缩放
和位移
影响了,简直就是身在三界外,不在五行中,就仿佛vector-effect
拥有了自己的领域一般变态。
<path id="ve" vector-effect="non-scaling-size non-rotation fixed-position" stroke="red" stroke-width="3" fill="none" transform="matrix(1,0, 0,1,150,150)" d="M-50,-50 L50,-50 50,-100 150,0 50,100 50,50 -50,50 -50,-50z M5 0 L0 -5 -5 0 0 5z"/ >
看看,看看这逆天的效果吧,难怪这厮要被封杀了,这哪是劳什子的矢量效果,这分明是要和无上意志平起平坐啊,这能不灭了你嘛。
结尾
在窥探了vector-effect
完全体的能力之后,对这些命运多舛却彪悍如斯的属性,突然多了很多期待,试想一下,若有一天,天下大赦,它们得以含冤昭雪,真到了那时前端世界又会是怎样一番光怪陆离的景象呢?
最后
最近找到一个VUE的文档,它将VUE的各个知识点进行了总结,整理成了《Vue 开发必须知道的36个技巧》。内容比较详实,对各个知识点的讲解也十分到位。
有需要的小伙伴,可以点击下方卡片领取,无偿分享