SVG之旅:填充特性

编辑推荐:诚征广告商金主入驻此广告位置,如有感兴趣的金主,欢迎邮件至:airenliao@gmail.com咨询相关合作事宜!!!(^_^)

通过前面的学习,你可以用你掌握的知识来绘制任何图形,接下来的目标是给绘制的图形着色。可以使用几种方法来着色,包括指定对象的属性,使用内联CSS样式或者内嵌的CSS样式,或者使用外部的CSS样式文件。大多数的Web网站的SVG使用的是内联样式CSS。但这些方法都有各自的优缺点。

在SVG中要给已绘制好的图形着色,我们主要通过SVG的填充和描边特性来完成。比如在前面的示例中,我们常能看到的fill属性,就是用来给图形设置填充颜色;stroke属性设置绘制对象的线条的颜色。但SVG的填充和描边特性不仅仅就这两个属性,那么今天的目标就是来学习这方面的特性。

首先我们要知道,在SVG中要让绘制的图形显示出来,就必须使用以下指定填充和描边特性:

SVG填充特性

属性名称 属性描述
fill 给绘制的图形填充颜色或图案,默认是black
fill-opacity 指定绘制图形填充的透明度,其值是0.0~1.0,其中0.0表示完全透明,1.0表示完全不透明,默认值是1.0
fill-rule 用来决定判断某个点是否在图形内部的方法,只有当边线交叉时或者内部有“洞”时和有效。属性值有nonzeroevenodd,其默认值是nonzero

SVG2的规范中涉及到有关于填充特性主要有上表所列的几个特性,但是在CSS 填充和描边模块(Level3)中除了上表的几个特性之外,还有fill-breakfill-colorfill-imagefill-originfill-positionfill-sizefill-repeat几个,看上去非常的类似于CSS中的background属性。

但在这篇文章中,只会初步的涉略上表中所列的几个填充特性,其他有关于填充的特性将会在其他的章节中进行介绍。

在这篇文章中,我们主要来了解和学习SVG中的fillfill-opacityfill-rule三个属性。

fill特性

在SVG中,可以使用fill给绘制的图形填充色,而填充色又分为三种:纯色渐变色图案。掌握这些技能,直接能决定你绘制的图形是否能引人入胜。

纯色填充

纯色填充其实没有什么特别,只需要在fill属性中添加颜色值就可以完成。其遵循的规则有:

  • 基本颜色名称,比如:aquablackblue这样的颜色关键词
  • SVG规范中规定的扩展颜色名称
  • 六位十六进制数字#rrggbb,从前往后,每两位分别表示redgreenblue颜色值
  • 三位十六进制数字#rgb,三位数字分别表示redgreenblue颜色值。这是六位十六进制数字#rrggbb的缩写
  • rgb(r,g,b)rgb分别是redgreenblue,其每个值的范围是0~2550%~100%
  • currentColor,来自元素的(当前运用的)color属性,一般是继承的
  • CSS3颜色模块规范规定的其他方法

说了这么多,我们来看一个简单的示例:

<svg  style="height: 300px;width: 100%;">
    <rect x="50" y="50" width="100" height="100" stroke="#000" stroke-width="10" fill="#f40" />   
    <rect x="170" y="50" width="100" height="100" stroke="#000" stroke-width="10" fill="#0f5" />  
    <rect x="290" y="50" width="100" height="100" stroke="#000" stroke-width="10" fill="#09f" />
</svg>

效果如下:

渐变填充

SVG中还可以使用渐变来填充,但这一部分咱们还没有接触过。而渐变又分为线性渐变、径向渐变和角度渐变。但在SVG中渐变的做法较为特殊,首先要先定义一个渐变层<defs>,接着让需要使用渐变的元件,指向这个已定义的渐变层。由于没有接触过SVG中的渐变相关的知识,但并不要紧,我们继续使用老办法,通过制图软件来绘制,然后导出相应的代码。 比如我们绘制了对应的三种渐变:

渐变填充

在绘制的时候,每一种都可以在对应的面板中选择颜色以及调整颜色的位置,比如:

渐变填充

接下来导出的.svg文件,查看清理后的代码:

<svg width="543px" height="162px" viewBox="0 0 543 162">
    <defs>
        <linearGradient x1="50%" y1="23.0100236%" x2="50%" y2="100%" id="linearGradient-1">
            <stop stop-color="#C33B35" offset="0%"></stop>
            <stop stop-color="#164AFB" offset="100%"></stop>
        </linearGradient>
        <rect id="path-2" x="0" y="0" width="167" height="159"></rect>
        <radialGradient cx="50%" cy="45.1700079%" fx="50%" fy="45.1700079%" r="76.9899764%" gradientTransform="translate(0.500000,0.451700),scale(0.952096,1.000000),rotate(90.000000),translate(-0.500000,-0.451700)" id="radialGradient-3">
            <stop stop-color="#C33B35" offset="0%"></stop>
            <stop stop-color="#164AFB" offset="100%"></stop>
        </radialGradient>
        <rect id="path-4" x="187" y="2" width="167" height="159"></rect>
        <rect id="path-5" x="376" y="3" width="167" height="159"></rect>
    </defs>
    <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
        <g id="Rectangle">
            <use fill="url(#linearGradient-1)" fill-rule="evenodd" xlink:href="#path-2"></use>
            <rect stroke="#000000" stroke-width="6" x="3" y="3" width="161" height="153"></rect>
        </g>
        <g id="Rectangle">
            <use fill="url(#radialGradient-3)" fill-rule="evenodd" xlink:href="#path-4"></use>
            <rect stroke="#000000" stroke-width="6" x="190" y="5" width="161" height="153"></rect>
        </g>
        <g id="Rectangle">
            <use fill="" fill-rule="evenodd" xlink:href="#path-5"></use>
            <rect stroke="#000000" stroke-width="6" x="379" y="6" width="161" height="153"></rect>
        </g>
    </g>
</svg>

上面实际效果中只有线性渐变和径向渐变生效,对于角度渐变是无效的:

至于为什么?暂时我也说不清楚。咱们先忽略。从上面的代码中,可以看到<defs>中包含了<linearGradient>(线性渐变)和<radialGradient>(径向渐变)。不管是哪种渐变,都通过<stop>来指定渐变的颜色和位置。把上面的代码简写一下:

<defs>
    <linearGradient id="lg">
        <stop stop-color="#C33B35" offset="0%"></stop>
        <stop stop-color="#164AFB" offset="100%"></stop>
    </linearGradient>

    <radialGradient id="rg">
        <stop stop-color="#C33B35" offset="0%"></stop>
        <stop stop-color="#164AFB" offset="100%"></stop>
    </radialGradient>
</defs>

分别给指定的渐变添加唯一的id名,这主要是为了让要引用渐变填充的元素可以有一个指向(更好引用)。至于<stop>中的stop-coloroffset起的作用,大家也许有些许了解,这也不是这里需要详细阐述的内容。

然后使用的时候,可以在fill中通过url(id)来引用,比如:

<rect x="50" y="50" width="100" height="100" stroke="#000" stroke-width="10" fill="url(#lg)" />   
<rect x="170" y="50" width="100" height="100" stroke="#000" stroke-width="10" fill="url(#rg)" /> 

有关于SVG中渐变更详细的介绍,我们在后续的文章中会阐述,这里只需要知道,在SVG中可以通过fill来做渐变填充即可。

图案填充

看完了渐变填充之后,再来看最后一个图案填充。其实现的方式和渐变有点类似,同要需要先在<defs>中加入<pattern>,这个pattern表示的是一个图案的区域,会用这个区域进行重复排列图案。同样在元素的fill属性中通过url(id)来调用<defs>中已声明的<pattern>,比如:

<svg width="543px" height="300px" viewBox="0 0 543 300">
    <defs>
        <pattern id="a2" patternUnits="userSpaceOnUse" x="0" y="0" width="30" height="30">
            <rect x="0" y="0" width="25" height="25" stroke="#none" fill="#09f"></rect>
        </pattern> 
    </defs>
    <rect x="170" y="50" width="135" height="135" stroke="#000" stroke-width="10" fill="url(#a2)" /> 
    <circle cx="420" cy="120" r="75" stroke="#000" stroke-width="5" fill="url(#a2)" />
</svg>

你将看到的效果如下:

fill-opacity特性

fill-opacity特性类似于CSS的opacity属性。用来设置元素填充的透明度。其值的范围不是0~1。接近0的值,元素填充更趋于透明,反之越接近1,则元素填充趋于完全不透明。其默认值为1。来看一个简单的示例:

<rect x="50" y="50" width="135" height="135" stroke="#000" stroke-width="10" fill="#f40" fill-opacity="0.3" />
<rect x="200" y="50" width="135" height="135" stroke="#000" stroke-width="10" fill="url(#a2)" fill-opacity="0.5"/> 
<circle cx="430" cy="120" r="75" stroke="#000" stroke-width="10" fill="url(#lg)" fill-opacity="0.9"/>

效果如下:

从上面的示例中,可以看出,不管是纯色、渐变还是图案填充,只要元素上使用了fill-opacity属性,都可以设置元素的填充透明度。

fill-rule特性

fill-rule特性相对而言要更复杂一些。其定义了判断点是不是属于填充范围的算法,其值有nonzeroevenoddinherit。咱们主要来了解nonzeroevenodd的算法。

nonzero

这个值采用的算法是:从需要判定的点向任意方向发射线,然后计算图形与线段交点的处的走向;计算结果从0开始,每有一个交点处的线段是从左到右的,就加1;每有一个交点处的线段是从右到左的,就减1;这样计算完所有交点后,如果这个计算的结果不等于0,则该点在图形内,需要填充;如果该值等于0,则在图形外,不需要填充。比如下图:

nonzero

来看一个示例:

<svg width="250px" height="250px" viewBox="0 0 250 250">
    <polygon fill="#F9F38C" fill-rule="nonzero" stroke="#E5D50C" stroke-width="5" stroke-linejoin="round" points="47.773,241.534 123.868,8.466 200.427,241.534 7.784,98.208 242.216,98.208 " />
</svg>
<svg width="250px" height="250px" viewBox="0 0 250 250">
    <path fill="#F4CF84" fill-rule="nonzero" stroke="#D07735" stroke-width="5" d="M124.999,202.856
    c-42.93,0-77.855-34.928-77.855-77.858s34.925-77.855,77.855-77.855s77.858,34.925,77.858,77.855S167.929,202.856,124.999,202.856z
    M125.003,245.385c-7.61,0-13.025-6.921-17.802-13.03c-2.79-3.559-6.259-8.002-8.654-8.638c-0.318-0.085-0.71-0.134-1.159-0.134 c-2.873,0-7.1,1.698-11.188,3.335c-4.929,1.973-10.029,4.021-14.774,4.021c-2.486,0-4.718-0.563-6.633-1.677 c-6.451-3.733-7.618-11.959-8.742-19.919c-0.646-4.571-1.45-10.261-3.292-12.096c-1.84-1.845-7.524-2.646-12.093-3.298 c-7.96-1.119-16.192-2.286-19.927-8.739c-3.682-6.358-0.614-14.005,2.35-21.404c1.829-4.563,3.904-9.735,3.201-12.352 c-0.638-2.392-5.073-5.861-8.64-8.648C11.539,138.025,4.618,132.612,4.618,125c0-7.61,6.921-13.025,13.027-17.802
    c3.567-2.79,8.002-6.259,8.64-8.651c0.702-2.614-1.375-7.789-3.201-12.349c-2.961-7.399-6.029-15.046-2.347-21.409 c3.733-6.451,11.962-7.618,19.924-8.742c4.569-0.646,10.253-1.45,12.096-3.292c1.84-1.84,2.646-7.524,3.29-12.093 c1.127-7.96,2.291-16.192,8.745-19.924c1.914-1.111,4.147-1.674,6.633-1.674c4.745,0,9.845,2.045,14.771,4.021 c4.085,1.639,8.312,3.335,11.188,3.335c0.446,0,0.836-0.045,1.161-0.131c2.392-0.641,5.861-5.079,8.654-8.643
    c4.782-6.109,10.194-13.03,17.804-13.03c7.612,0,13.025,6.921,17.804,13.027c2.782,3.565,6.259,8.002,8.654,8.643 c0.323,0.085,0.71,0.131,1.161,0.131c2.876,0,7.094-1.696,11.185-3.332c4.932-1.976,10.029-4.021,14.779-4.021 c2.478,0,4.715,0.563,6.627,1.671c6.448,3.733,7.618,11.962,8.739,19.927c0.646,4.569,1.453,10.253,3.292,12.093 c1.84,1.84,7.524,2.646,12.096,3.292c7.96,1.127,16.189,2.291,19.919,8.745c3.687,6.36,0.619,14.007-2.344,21.404
    c-1.824,4.563-3.898,9.735-3.201,12.347c0.641,2.395,5.079,5.864,8.643,8.657c6.104,4.774,13.025,10.189,13.025,17.799 c0,7.612-6.921,13.025-13.03,17.804c-3.559,2.788-8.002,6.264-8.638,8.654c-0.702,2.614,1.375,7.783,3.201,12.347 c2.964,7.399,6.032,15.046,2.344,21.409c-3.733,6.448-11.959,7.618-19.924,8.739c-4.566,0.646-10.256,1.453-12.09,3.292 c-1.845,1.84-2.646,7.524-3.298,12.096c-1.119,7.96-2.291,16.189-8.745,19.919c-1.909,1.113-4.147,1.677-6.627,1.677 c-4.745,0-9.839-2.048-14.768-4.021c-4.091-1.637-8.315-3.335-11.19-3.335c-0.446,0-0.836,0.048-1.161,0.134 c-2.392,0.635-5.861,5.073-8.648,8.638C138.027,238.464,132.615,245.385,125.003,245.385z" />
</svg>

效果如下:

星星是由一条相交的路径组成的,太阳则是由一条长复合的路径组成。每个形状的内部最初并不清楚,可能根据作者的意图而有所不同。在这些情况下,fill-rule允许进一步澄清。

在下一个例子中,我们可以看得更清楚些,当nonzero算法被应用到类似的图形时,究竟发生了什么?

nonzero

从上图中我们可以理解成,当方向是顺时针时,加1,逆时针时减1。相交的值不等于0则填充,如果等于0则不填充。

evenodd

这个值采用的算法是,从需要判定的点向任意方向发射线,然后计算图形与线段交点的个数,个数为奇数则该点在图形内,则需要填充;个数为偶数,则该点在图形外,不需要填充。如下图所示:

evenodd

上面的示例稍作调整:

<svg width="250px" height="250px" viewBox="0 0 250 250">
    <polygon fill="#F9F38C" fill-rule="evenodd" stroke="#E5D50C" stroke-width="5" stroke-linejoin="round" points="47.773,241.534 123.868,8.466 200.427,241.534 7.784,98.208 242.216,98.208 " />
</svg>
<svg width="250px" height="250px" viewBox="0 0 250 250">
    <path fill="#F4CF84" fill-rule="evenodd" stroke="#D07735" stroke-width="5" d="M124.999,202.856
    c-42.93,0-77.855-34.928-77.855-77.858s34.925-77.855,77.855-77.855s77.858,34.925,77.858,77.855S167.929,202.856,124.999,202.856z
    M125.003,245.385c-7.61,0-13.025-6.921-17.802-13.03c-2.79-3.559-6.259-8.002-8.654-8.638c-0.318-0.085-0.71-0.134-1.159-0.134 c-2.873,0-7.1,1.698-11.188,3.335c-4.929,1.973-10.029,4.021-14.774,4.021c-2.486,0-4.718-0.563-6.633-1.677 c-6.451-3.733-7.618-11.959-8.742-19.919c-0.646-4.571-1.45-10.261-3.292-12.096c-1.84-1.845-7.524-2.646-12.093-3.298 c-7.96-1.119-16.192-2.286-19.927-8.739c-3.682-6.358-0.614-14.005,2.35-21.404c1.829-4.563,3.904-9.735,3.201-12.352 c-0.638-2.392-5.073-5.861-8.64-8.648C11.539,138.025,4.618,132.612,4.618,125c0-7.61,6.921-13.025,13.027-17.802
    c3.567-2.79,8.002-6.259,8.64-8.651c0.702-2.614-1.375-7.789-3.201-12.349c-2.961-7.399-6.029-15.046-2.347-21.409 c3.733-6.451,11.962-7.618,19.924-8.742c4.569-0.646,10.253-1.45,12.096-3.292c1.84-1.84,2.646-7.524,3.29-12.093 c1.127-7.96,2.291-16.192,8.745-19.924c1.914-1.111,4.147-1.674,6.633-1.674c4.745,0,9.845,2.045,14.771,4.021 c4.085,1.639,8.312,3.335,11.188,3.335c0.446,0,0.836-0.045,1.161-0.131c2.392-0.641,5.861-5.079,8.654-8.643
    c4.782-6.109,10.194-13.03,17.804-13.03c7.612,0,13.025,6.921,17.804,13.027c2.782,3.565,6.259,8.002,8.654,8.643 c0.323,0.085,0.71,0.131,1.161,0.131c2.876,0,7.094-1.696,11.185-3.332c4.932-1.976,10.029-4.021,14.779-4.021 c2.478,0,4.715,0.563,6.627,1.671c6.448,3.733,7.618,11.962,8.739,19.927c0.646,4.569,1.453,10.253,3.292,12.093 c1.84,1.84,7.524,2.646,12.096,3.292c7.96,1.127,16.189,2.291,19.919,8.745c3.687,6.36,0.619,14.007-2.344,21.404
    c-1.824,4.563-3.898,9.735-3.201,12.347c0.641,2.395,5.079,5.864,8.643,8.657c6.104,4.774,13.025,10.189,13.025,17.799 c0,7.612-6.921,13.025-13.03,17.804c-3.559,2.788-8.002,6.264-8.638,8.654c-0.702,2.614,1.375,7.783,3.201,12.347 c2.964,7.399,6.032,15.046,2.344,21.409c-3.733,6.448-11.959,7.618-19.924,8.739c-4.566,0.646-10.256,1.453-12.09,3.292 c-1.845,1.84-2.646,7.524-3.298,12.096c-1.119,7.96-2.291,16.189-8.745,19.919c-1.909,1.113-4.147,1.677-6.627,1.677 c-4.745,0-9.839-2.048-14.768-4.021c-4.091-1.637-8.315-3.335-11.19-3.335c-0.446,0-0.836,0.048-1.161,0.134 c-2.392,0.635-5.861,5.073-8.648,8.638C138.027,238.464,132.615,245.385,125.003,245.385z" />
</svg>

运用fill-rule="evenodd"的星星和太阳的效果就和刚才的不一样了:

同样用一张图来描述,可能更易于理解:

evenodd

evenodd规则是特定的算法,与nonzero情况不同,其算法和内部形状绘制的方向不相关,因为只是简单地计算它们穿过直线的路径数是不是奇偶数。

上面我们了解了SVG中的填充特性,除此之外,还有描边特性:

属性名称 属性描述
stroke 描边的颜色,默认值为black
stroke-width 描边的宽度,可用用户坐标或指定单位的方式指定。描边的宽度会相对坐标网格线居中。默认值为1
stroke-opacity 指定描边的透明度,其值是从0.0~1.00.0表示完全透明,1.0表示完全不透明,默认值为1.0
stroke-dasharray 用一系列的数字来指定虚线和间隙的长度。默认值为none
stroke-linecap 指定线头尾的形状,其值有buttroundsquare,默认值为butt
stroke-linejoin 图形的棱角或者一系列连线的形状,其值有miterroundbevel,默认值为miter
stroke-miterlimit 相交处显示宽度与线宽的最大比例,默认值为4

SVG2的规范中,除了上表所列之外的特性,还有stroke-dashoffset。但在CSS 填充和描边模块(Level3)中除了上述所列的几个特性之外,还有以下一些特性:stroke-breakstroke-dash-cornerstroke-dash-justifystroke-colorstroke-imagestroke-originstroke-positionstroke-sizestroke-repeat等特性。

由于担心篇幅过长,将SVG的描边特性放到下一节中来阐述。

使用CSS

除了定义对象的属性外,你也可以通过CSS来样式化填充(当然后面的描边也可以)。语法和在HTML中使用CSS一样,只不过你要把background-color换成fill

需要特别注意的是,在SVG中不是所有的属性都能用CSS来设置。上色和填充的部分一般是可以用CSS来设置的,比如fill,但是不包括上面提到的渐变和图案等功能。另外,widthheight以及path的命令等,都不能用CSS来设置。判断它们能不能用CSS设置还是比较容易的。

SVG规范将属性区分成properties和其他attributes,前者是可以用CSS来设置,后者则不能。

用简单的示例来展示,更为明显:

<defs>
    <style type="text/css"><![CDATA[
    #MyRect {
        stroke: black;
        fill: red;
    }
    ]]></style>
</defs>
<rect x="10" height="180" y="10" width="180" id="MyRect"/>

或者:

<rect x="10" height="180" y="10" width="180" style="stroke: black; fill: red;"/>

你也还可以在单独的.css文件中使用:

#MyRect {
    fill: red;
}

总结

前面的内容我们是学习了在SVG中怎么绘制图形。事实上,在SVG中绘制的图形要着色的话是需要通过其他的特性来完成的,比如填充就需要fill特性。而在这篇文章中,主要学习了如何给绘制的元素填充(纯色、渐变和图案)。主要涉及到三个属性:fill用来填充颜色(或图案),fill-opacity用来设置填充的透明度和fill-rule用来指定判断填充的算法

在SVG中绘制的图形除了填充之外,还有描边着色之类的。比如文章列表中提到的描边特性。那么在下一篇文章中,将主要来学习这方面的知识。如果你感兴趣的话,欢迎持续观注本系列的相关更新。

由于本人是SVG的初学者,如果文章中有不对之处,烦请各路大婶拍正。如果你有更好的经验或想法,欢迎在下面的评论中与我们一起分享。

上一节下一节

大漠

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

如需转载,烦请注明出处:https://www.w3cplus.com/svg/svg-fill-features.html

返回顶部