SVG之旅:描边特性

发布于 大漠

上一节介绍SVG填充特性中,提到了SVG中另一个特性描边特性(stroke。SVG的描边特性主要包括strokestroke-widthstroke-opacitystroke-dasharraystroke-linecapstroke-linejoinstroke-miterlimit等属性。在这一节中,主要围绕这几个SVG属性进行展开。

在SVG中咱们通过stroke来对绘制的图形边框进行设置,我们可以对图形边框的颜色、粗细、透明度,连接端,线帽和虚线等进行设置。为了更好的理解SVG中的描边特性,我们采用一个葡萄的轮廓图来展开介绍。

特别声明:接下来的葡萄轮廓图来自于@jonitrythall的《Using SVG stroke Attributes》一文中。

stroke

stroke属性主要用来定义SVG绘制的形状和路径的边框颜色。类似于CSS中的border-color。和fill特性一样,可以在SVG的内联代码中使用stroke属性,也可以在CSS样式代码中使用stroke属性。如果想让SVG绘制的图形不带有任何边框,只需要设置stroke的值为none即可。如果你不设置任何的颜色值,那么默认的颜色为black

<svg width="250px" height="265px" viewBox="0 0 150 165">
    <path class="grapes" fill="none" stroke="#765373" d=".../>
    <g>
        <path class="stem" fill="none" stroke="#59351C" d="..."/>
        <path class="leaf" fill="#7AA20D" stroke="#7AA20D" d=" ..."/>
    </g>
</svg>

stroke-width

stroke-width属性的值用来设置绘制图形边框的宽度,类似于border-width。其默认值是1。如果值是百分数,那这个值是基于视图的尺寸来计算。比如,下面的示例,把葡萄的边框宽度设置为6px、葡萄的茎设置为5px,叶子设置为2px

<svg width="250px" height="265px" viewBox="0 0 150 165">
    <path class="grapes" fill="none" stroke="#765373" stroke-width="6" d="..."/>
    <g>
        <path class="stem" fill="none" stroke="#59351C" stroke-width="5" d="..."/>
        <path class="leaf" fill="#7AA20D" stroke="#7AA20D" stroke-width="2" d="..."/>
    </g>
</svg>

stroke-linecap

当使用<line>或者<polyline>画线时,可以给stroke-linecap指定不同的值来确定线的头尾形状。也就是说,给一个开放路径的定义端点采用哪种形状。其主要有四个值:buttroundsquareinherit。对应的效果如下:

stroke-linecap

把葡萄的边框设置为butt、葡萄的茎设置为square,葡萄的叶子设置为round

<svg width="250px" height="265px" viewBox="0 0 150 165">
    <path class="grapes" fill="none" stroke="#765373" stroke-width="6" stroke-linecap="butt" d="..."/>
    <g>
        <path class="stem" fill="none" stroke="#59351C" stroke-width="5" stroke-linecap="square" d="..."/>
        <path class="leaf" fill="#7AA20D" stroke="#7AA20D" stroke-width="2" stroke-linecap="round" d="..."/>
    </g>
</svg>
‘butt’ cap
        <g transform="translate(150,0)">
            <path fill="none" stroke="#444" stroke-width="20" d="M 100,100 C 200,100 100,200 200,150"/>
            <path fill="none" stroke="#ccc" stroke-width="2" d="M 100,100 C 200,100 100,200 200,150"/>
            <path fill="deeppink" d="M 100,90 A 10,10 0 0 0 100,110"/>
            <path fill="deeppink" d="M 100,90 A 10,10 0 0 0 100,110" transform="translate(100,50) rotate(155,100,100)"/>
            <g stroke="#ccc" stroke-width="1">
                <g stroke="#6a9100">
                    <path d="M 60,100 h 80" transform="rotate(90,100,100)"/>
                    <path d="M -40,0 h 80" transform="translate(200,150) rotate(65)"/>
                </g>
            </g>
            <text x="150" y="40">‘round’ cap</text>
        </g>

        <g transform="translate(330,0)">
            <path fill="none" stroke="#444" stroke-width="20" d="M 100,100 C 200,100 100,200 200,150"/>
            <path fill="none" stroke="#ccc" stroke-width="2" d="M 100,100 C 200,100 100,200 200,150"/>
            <path fill="deeppink" d="M 100,90 v 20 h -10 v -20 z"/>
            <path fill="deeppink" d="M 100,90 v 20 h -10 v -20 z" transform="translate(100,50) rotate(155,100,100)"/>
            <g stroke="#ccc" stroke-width="1">
                <g stroke="#6a9100">
                    <path d="M 60,100 h 80" transform="rotate(90,100,100)"/>
                    <path d="M -40,0 h 80" transform="translate(200,150) rotate(65)"/>
                </g>
            </g>
            <text x="150" y="40">‘square’ cap</text>
        </g>

        <g transform="translate(-30,130)">
            <g transform="translate(0,-10)">
                <path d="M 80,150 h 142" stroke="#aaa" stroke-width="140" stroke-dasharray="1 9"/>
                <path d="M 150,80 v 142" stroke="#aaa" stroke-width="140" stroke-dasharray="1 9"/>
            </g>
            <path fill="none" stroke="#444" stroke-width="20" d="M 100,100 C 200,100 100,200 200,150"/>
            <path fill="none" stroke="#ccc" stroke-width="2" d="M 100,100 C 200,100 100,200 200,150"/>
        </g>

        <g transform="translate(150,130)">
            <g transform="translate(0,-10)">
                <path d="M 80,150 h 142" stroke="#aaa" stroke-width="140" stroke-dasharray="1 9"/>
                <path d="M 150,80 v 142" stroke="#aaa" stroke-width="140" stroke-dasharray="1 9"/>
            </g>
            <path fill="none" stroke="#444" stroke-width="20" stroke-linecap="round" d="M 100,100 C 200,100 100,200 200,150"/>
            <path fill="none" stroke="#ccc" stroke-width="2" d="M 100,100 C 200,100 100,200 200,150"/>
        </g>

        <g transform="translate(330,130)">
            <g transform="translate(0,-10)">
                <path d="M 80,150 h 142" stroke="#aaa" stroke-width="140" stroke-dasharray="1 9"/>
                <path d="M 150,80 v 142" stroke="#aaa" stroke-width="140" stroke-dasharray="1 9"/>
            </g>
            <path fill="none" stroke="#444" stroke-width="20" stroke-linecap="square" d="M 100,100 C 200,100 100,200 200,150"/>
            <path fill="none" stroke="#ccc" stroke-width="2" d="M 100,100 C 200,100 100,200 200,150"/>
        </g>
    </g>
</svg>

其中使用round有一点需要注意,round是有半径的圆弧形,直径就是stroke-width的值。

stroke-linejoin

stroke-linejoin定义画笔在路径和基本形状上的转角如何展示。言外之意,用来指定线段在图形棱角处交叉时的效果。其主要有四值值:miter(尖的)、round(圆的)、bevel(平的)和inherit

stroke-linejoin

比如下面的示例,我们将葡萄的转角linejoin属性从round改变成bevel时发生的变化:

<svg width="250px" height="265px" viewBox="0 0 150 165">
    <path class="grapes" fill="none" stroke="#765373" stroke-width="6" stroke-linecap="round" stroke-linejoin="bevel" d="..."/>
    <g>
        <path class="stem" fill="none" stroke="#59351C" stroke-width="5" stroke-linecap="round" d="..."/>
        <path class="leaf" fill="#7AA20D" stroke="#7AA20D" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" d="..."/>
    </g>
</svg>

同样为了更易理解,用下图来帮助大家理解:

‘miter’ join ‘round’ join ‘bevel’ join ‘arcs’ join

stroke-miterlimit

当两条线相遇会形成一个尖角,并且设置了stroke-linejoin="miter"时,stroke-miterlimit属性就是允许这个交汇处/转角可延伸到多远的距离。交汇处的长度也被称为斜接长度,测量的是交汇处内角和外角之间的距离。

    <g transform="translate(0,0)">
        <use class="thick" xlink:href="#Demo2path1" stroke-linejoin="miter" style="stroke:black"/>
        <use class="thin" xlink:href="#Demo2path1"/>
        <use xlink:href="#Demo2circle1"/>
        <use xlink:href="#Demo2limit1"/>
        <use xlink:href="#Demo2limit2"/>
        <text x="175" y="140">miter length</text>
        <path d="m 130,137 -40,0" style="fill:none;stroke:black;marker-end:url(#Demo2arrow1)"/>
        <path d="m 220,137  40,0" style="fill:none;stroke:black;marker-end:url(#Demo2arrow1)"/>
    </g>

    <g transform="translate(300,0)">
        <use class="thick" xlink:href="#Demo2path1" stroke-linejoin="miter" style="stroke:black;clip-path:url(#Demo2clip1)"/>
        <use class="thin" xlink:href="#Demo2path1"/>
        <use class="thick2" xlink:href="#Demo2path2" style="clip-path:url(#Demo2clip1)"/>
        <use class="thin" xlink:href="#Demo2path2"/>
        <use xlink:href="#Demo2circle1"/>
        <use xlink:href="#Demo2limit"/>
    </g>
</svg>

stroke-miterlimit接受两个值:mitermiter-clip。两者交汇处效果的对比如下:

<g transform="translate(0,0)">
    <use class="thick" xlink:href="#Demo3path1" stroke-linejoin="miter"/>
    <use class="thick" xlink:href="#Demo3path1" stroke-linejoin="bevel" style="stroke:black"/>
    <use class="thin" xlink:href="#Demo3path1"/>
    <use xlink:href="#Demo3circle1"/>
    <use xlink:href="#Demo3limit"/>
    <text x="150" y="150">‘miter’ join</text>
</g>

<g transform="translate(300,0)">
    <use class="thick" xlink:href="#Demo3path1" stroke-linejoin="miter"/>
    <use class="thick" xlink:href="#Demo3path1" stroke-linejoin="miter" style="stroke:black;clip-path:url(#Demo3clip1)"/>
    <use class="thin" xlink:href="#Demo3path1"/>
    <use xlink:href="#Demo3circle1"/>
    <use xlink:href="#Demo3limit"/>
    <text x="150" y="150">‘miter-clip’ join</text>
</g>
</svg>

事实上,这个值就是斜接长度和stroke-width的比值的一个界限值。1.0是该属性的最小可能值。

下面的葡萄设置了stroke-miterlimit="1.0",形成一种斜角效果。第二幅的stroke-miterlimit="4.0"

<svg width="250px" height="265px" viewBox="0 0 150 165">
    <path class="grapes" fill="none" stroke="#765373" stroke-width="6" stroke-linecap="round" stroke-linejoin="miter" stroke-miterlimit="1.0" d="..."/>
    <g>
        <path class="stem" fill="none" stroke="#59351C" stroke-width="5" stroke-linecap="round" d="..."/>
        <path class="leaf" fill="#7AA20D" stroke="#7AA20D" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" d="..."/>
    </g>
</svg>
<svg width="250px" height="265px" viewBox="0 0 150 165">
    <path class="grapes" fill="none" stroke="#765373" stroke-width="6" stroke-linecap="round" stroke-linejoin="miter" stroke-miterlimit="4.0" d="..."/>
    <g>
        <path class="stem" fill="none" stroke="#59351C" stroke-width="5" stroke-linecap="round" d="..."/>
        <path class="leaf" fill="#7AA20D" stroke="#7AA20D" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" d="..."/>
    </g>
</svg>

效果如下:

stroke-dasharray

stroke-dasharray属性允许我们将路径转换成虚线而不是实线。通过这个属性,可以指定虚线的长度及以虚线之间的距离,用逗号或空格分开。

如果提供的值有奇数个,那这个列会重复产生至偶数个值。比如,8,6,4变成8,6,4,8,6,4,正如下面展示的第二个葡萄。在这个值中只放一个数字,导致虚线之间会有一个和一条虚线长度个等的空隙。在这个值中只放一个数字,导致在虚线之间会有一个和一条虚线长度相等的空隙。

<svg width="250px" height="265px" viewBox="0 0 150 165">
    <path class="grapes" fill="none" stroke="#765373" stroke-width="6" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="20,15,10,8" d="..."/>
    <g>
        <path class="stem" fill="none" stroke="#59351C" stroke-width="5" stroke-linecap="round" d="..."/>
        <path class="leaf" fill="#7AA20D" stroke="#7AA20D" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" d="..."/>
    </g>
</svg>
<svg width="250px" height="265px" viewBox="0 0 150 165">
    <path class="grapes" fill="none" stroke="#765373" stroke-width="6" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="8,6,4" d="..."/>
    <g>
        <path class="stem" fill="none" stroke="#59351C" stroke-width="5" stroke-linecap="round" d="..."/>
        <path class="leaf" fill="#7AA20D" stroke="#7AA20D" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" d="..."/>
    </g>
</svg>

stroke-dashoffset

stroke-dashoffset指定虚线的起始偏移距离。

<svg width="250px" height="265px" viewBox="0 0 150 165">
    <path class="grapes" fill="none" stroke="#765373" stroke-width="6" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="40,10" stroke-dashoffset="35" d="..."/>
    <g>
        <path class="stem" fill="none" stroke="#59351C" stroke-width="5" stroke-linecap="round" d="..."/>
        <path class="leaf" fill="#7AA20D" stroke="#7AA20D" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" d="..."/>
    </g>
</svg>

效果如下:

在上面的例子中,我们将虚线设置成40px长,dashoffset35px。在路径的起点,虚线有35px是不可见的,在35px40px之间显示虚线,这就是为什么第一段虚线显示的格外的短。

为了能让大家更好的理解stroke-dasharraystroke-dashoffset,可以通过下图来理解:

也可以拖动下面示例中的进度条来看效果:

stroke-opacity

stroke-opacity属性很直观,就是允许我们在图形上设置一个透明度。这个值是01中的小数,0表示完全透明。比如下面的示例效果:

<svg width="250px" height="265px" viewBox="0 0 150 165">
    <path class="grapes" fill="none" stroke="#765373" stroke-width="6" stroke-linecap="round" stroke-linejoin="miter" stroke-miterlimit="1.0" stroke-opacity
="0.5" d="..."/>
    <g>
        <path class="stem" fill="none" stroke="#59351C" stroke-width="5" stroke-linecap="round" stroke-opacity="0.2" d="..."/>
        <path class="leaf" fill="#7AA20D" stroke="#7AA20D" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" stroke-opacity="0.8" d="..."/>
    </g>
</svg>    

示例中葡萄边框的透明度设置为stroke-opacity="0.5",葡萄的茎设置为stroke-opacity="0.2",葡萄的叶子设置为stroke-opacity="0.8"

SVG的线条动画

stroke属性可以动起来的。这样可以创作一些独一无二的效果,比如,当你的路径的stroke-sashoffset动画描绘出来的时候。

为了让下面第一个葡萄的路径显示成“画出来”的效果,stroke-dasharray设置成刚好覆盖整条路径的虚线长度。然后设置一个匹配的stroke-dashoffset也是足够长可以覆盖路径。暂时让整个路径基本上看不到。

通过 @keyframes drawstroke-dashoffset在50%的点设回到0,让它显示的就好像正在画自己,也好像在回放。

第二幅葡萄的stroke-dasharray70px,通过 @keyframes shift,我们将动画效果设置成进行到一半的时候stroke-dashoffset200px

为了更好的看清楚,咱们把上面的Demo修改一下:

.grapes {
    stroke-dashoffset: 10;
    stroke-dasharray: 30 5;
    stroke-width: 3;
}

通过浏览器的编辑器来修改stroke-dashoffset的值:

总结

这篇文章咱们主要学习了一下SVG中描边相关的属性的使用。可以通过stroke相关的属性,给绘制的形状或路径设置边框(描边)的颜色、粗线、线型、透明度,线帽等。另外配合CSS的animation来修改stroke-dashoffset的值,还可以绘制出一些很有意思的效果。比如上面的动画效果。事实上,在SVG通过stroke-dashoffsetstroke-dasharray可以完成很多线形动效,很多人称之为线型之美。那么下一接咱们就来学学SVG的线型之美。希望大家会喜欢。

上一节下一节

大漠

常用昵称“大漠”,W3CPlus创始人,目前就职于手淘。对HTML5、CSS3和Sass等前端脚本语言有非常深入的认识和丰富的实践经验,尤其专注对CSS3的研究,是国内最早研究和使用CSS3技术的一批人。CSS3、Sass和Drupal中国布道者。2014年出版《图解CSS3:核心技术与案例实战》。

如需转载,烦请注明出处:https://www.fedev.cn/svg/svg-stroke.htmljordan retro 11 mens size