likes
comments
collection
share

SVG奇淫巧技(八):比冷门还冷门的vector-effect

作者站长头像
站长
· 阅读数 21

我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第8篇文章。

vector-effectSVG中十分冷门的属性,相信大多数小伙伴都没有了解过,说句实话,在这次重学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时的效果,所以也是最常见的,毕竟这么冷门的属性谁会没事去指定一下呢?

SVG奇淫巧技(八):比冷门还冷门的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后,iconstoke也就是所谓的笔触,也同样被放大了。

其实,仔细想想,这是符合SVG矢量特性的,试想一下,一个stroke-width=1的图形,要是被放大到一个大屏上,那么stroke如果不随着图形的增大而变粗,那么在远处看过去几乎已经无法看清了。

但是,不得不说如此放大之后,在一些小屏幕上看着好突兀,那么有没有什么办法可以在SVG缩放的时候stroke不跟着缩放呢?

当然是有的,下面有请non-scaling-stroke上场。

让stroke跳脱出矢量效果的non-scaling-stroke

non-scaling-stroke: 该值修改了笔触的方式。通常,笔触涉及在当前用户坐标系中计算形状路径的笔触轮廓,并用笔触颜料(颜色或渐变)填充轮廓。该值的最终视觉效果是笔触宽度不依赖于元素的变换(包括非均匀缩放和剪切变换)和缩放级别。

定义是不是依旧看的云里雾里,没关系,一图胜千言:

SVG奇淫巧技(八):比冷门还冷门的vector-effect

.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-effecticon形成了鲜明的对比。

值得注意的是,无论是<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奇淫巧技(八):比冷门还冷门的vector-effect

<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奇淫巧技(八):比冷门还冷门的vector-effect

<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>

好了,掌握了nonenon-scaling-stroke,就相当于弄懂了整个vector-effect属性,虽然它还有另外3个看似很厉害的可选值,但那3个值属实是有点“不堪重用”

不堪重用的另外3个可选值

这里的“不堪重用”并不是说他们不好用,而是压根用不了(这里的测试只针对Chrome而言)。

SVG奇淫巧技(八):比冷门还冷门的vector-effect

之所以会这样,是因为 Scalable Vector Graphics (SVG) 1.1 (Second Edition)的规范中明确指出这3个属性有可能会从SVG 2的规范中删除,全文如下:

Values of vector-effect other than non-scaling-stroke and none 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.

大概就是说,那哥仨还是有点不靠谱,所以除了nonenon-scaling-stroke 被豁免之外,其他属性都有可能从SVG2的规范中被删除。

所以,Chrome对这种有连坐风险的属性不支持也就变得情有可原了。

虽然,浏览器不支持,规范要删除,但这都不妨碍我们来一窥这哥仨的全貌。

non-scaling-size

non-scaling-size: 该值指定元素及其后代使用的特殊用户坐标系。尽管从宿主坐标空间进行任何转换更改,该用户坐标系的比例也不会更改。但是,它没有指定抑制旋转和偏斜。同样,它也不指定用户坐标系的原点。由于此值抑制了用户坐标系的缩放,因此它还具有non-scaling-stroke的特性。

大概就是说这个属性可以让指定元素不受坐标系缩放效果的影响。

SVG奇淫巧技(八):比冷门还冷门的vector-effect

<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-strokenon-scaling-size相比:

non-scaling-stroke:只有stroke描边的宽度不会被缩放,至于fill或图形的宽高依旧会进行缩放。

non-scaling-size: 无论是strokefill宽高都不会进行缩放,也就是说缩放在non-scaling-size面前彻底失效了,换句话说它属于non-scaling-stroke的上位替代。

non-rotation

non-rotation: 该值指定元素及其后代使用的特殊用户坐标系。尽管从宿主坐标空间发生任何变换更改,该用户坐标系的旋转和倾斜仍被抑制。但是,它没有指定抑制缩放。同样,它也没有指定用户坐标系的原点。

有了上面缩放的案例,这里就要好理解多了,顾名思义不旋转

SVG奇淫巧技(八):比冷门还冷门的vector-effect

<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的效果影响。

SVG奇淫巧技(八):比冷门还冷门的vector-effect

可以看到,虽然坐标系被缩放和旋转了,但是箭头图案中的锚点位置是固定的并没有随着坐标系的改变而改变。

vector-effect的属性组合使用

与其他属性不同vector-effect是可以组合使用的,只不过目前只有nonenon-scaling-stroke可用,况且这两货还互相冲突的属性,所以组合的意义不大,但是换成以上那哥仨效果一下就有趣了起来。

试想一下,哥仨同时生效之后,就代表着指定元素不受任何转换旋转缩放位移影响了,简直就是身在三界外,不在五行中,就仿佛vector-effect拥有了自己的领域一般变态。

SVG奇淫巧技(八):比冷门还冷门的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完全体的能力之后,对这些命运多舛却彪悍如斯的属性,突然多了很多期待,试想一下,若有一天,天下大赦,它们得以含冤昭雪,真到了那时前端世界又会是怎样一番光怪陆离的景象呢?

参考文献

MDN-# vector-effect

转载自:https://juejin.cn/post/7147888942199603237
评论
请登录