前端开发者学堂 - fedev.cn

SVG基础——填充和描边

发布于 彦子

过去几周我讲解了可缩放矢量图形(SVG)的一些基础知识。首先,我展示了如何在HTML中嵌入SVG,接着讲解了如何创建SVG预定义的基础图形

为了让创建的图形显示出来,我在这两篇文章中都使用了填充和描边属性。今天我想要详细讲讲填充和描边以及它们的一些相关的属性。

填充属性

正如你所理解的,填充属性就是用你选定的颜色来填充你创建的图形(或线条)的内部区域。这是使用了填充的矩形和圆形:

<rect class="rectangle" width="100%" height="100%" fill="red" />
<circle class="circle" cx="150" cy="150" r="100" fill="#039" />

你也可以在你的CSS中设置填充值,下面我在不同的class类中设置了填充。但是如果你喜欢的话,你也可以直接在SVG属性中设置。

.rectangle {fill: red;}
.circle {fill: #039;}

默认情况下的填充颜色是 black 或者 #000000 ,所以如果你不想要你的图形被填充的话,你需要显式地设置 fillnone

<rect class="rectangle" width="100%" height="100%" fill="none" />

fill-rule 属性

关于图形(或线条)的内部区域,是由 fill-rule 属性决定的,它有 nonzeroevenodd 两个值:

fill-rule="nonzero"
fill-rule="evenodd"

我并不打算假装我是完全了解这两种算法是如何工作的。下面是官方定义。还有来自规范文件的这两个算法分别的示例图像:

nonzero—这个规则通过从canvas上的某个点往任一方向绘制射线到无穷远,然后检查图形的线段和射线相交的点,来确定“内部区域”。从0开始计数,每次路径线段是从左到右穿过射线就加一,从右到左的就减一。通过计算交叉点,如果结果是0,则这个点在路径外边,不然,就是在里边。

SVG

evenodd—这个规则通过从canvas上某个点往任一方向绘制射线到无穷远,然后计算给定图形上线段路径和该射线交叉点的数量。如果这个数是奇数,那么该点在图形内部;如果是偶数,该点在图形外部。

svg

让我觉得困惑的是这两组SVG图形的最后一个示例。我不明白为什么它们明明是一样的图形,可是第二组示例的结果却不一样。如果有谁能解释一下的话,我会很感激的。

fill-opacity 属性

你还可以设置填充的 fill-opacity 属性。

fill-opacity="0.5"

它的取值应在0(透明)和1(不透明)之间,和CSS的opacity属性一样,我想也不需要我进一步解释了吧。

描边属性

填充属性可以帮你在元素内部添加颜色,而描边属性则可以在元素周围添加颜色,它们定义了元素的轮廓

strokestroke-width 属性

描边比填充多几个属性,而且坦白说,我觉得它们都挺有趣的。如果你看过这个系列的前几篇文章,你应该已经看到两个描边属性了, strokestroke-width 。第一个属性接受一个颜色值,第二个属性取一组测量值。

stroke="blue"
stroke="#347559

stroke-width="3px"
stroke-width="1em"
stroke-width="2%"

stroke-width 的值为百分比时,表示它是当前视图的百分比值。

<svg width="300px" height="150px">
  <ellipse cx="150" cy="75" rx="100" ry="75" fill="none" stroke="blue" stroke-width="3px" />
</svg>

stroke-opacity 属性

还有一个 stroke-opacity 属性,我想也不需要再详细说明了吧。

stroke-opacity="0.25"

stroke-linecap 属性

还有 stroke-linecap 属性可以让你在线条末端控制图形。你可以选择对接(butt)、方形(square)和圆形(round),可以在下边的图片中看到对应的示例效果:

svg

stroke-linejoin 属性

stroke-linejoin 属性也是类似的,但是它控制的是两条线段之间的衔接。你可以在绘制折线时使用它。它有三个值,尖角(miter)、圆角(round)和斜角(bevel),可以在下面的图片中看到对应的效果:

svg

如果你设置 miter 作为 linejoin 的值,它的线条就会呈锐角连接,而且尖角可能超过了描边的厚度。

stroke-miterlimit 属性

stroke-miterlimit 属性给 miter-lengthstroke-width 之间的比率做了限制,它的比值范围应大于或等于1。当比值不在这个范围的时候, stroke 就会被转换成斜角(bevel)。

stroke-dasharray 属性

stroke-dasharray 是用于设置虚线的属性。你可以使用它来设置每条划线长度以及划线之间空格的大小。

<svg width="600px" height="300px">
  <line x1="0" y1="20" x2="600" y2="20" stroke="#000" stroke-width="3" stroke-dasharray="10 2" />
  <line x1="0" y1="40" x2="600" y2="40" stroke="#000" stroke-width="3" stroke-dasharray="5 10" />
  <line x1="0" y1="60" x2="600" y2="60" stroke="#000" stroke-width="3" stroke-dasharray="1 1" />
  <line x1="0" y1="80" x2="600" y2="80" stroke="#000" stroke-width="3" stroke-dasharray="10" />
</svg>

第一个值是划线的长度,第二个值是各个划线之间的空格大小。如果你只设置了一个值(如上面的最后一个示例),它会默认设置相同划线长度和划线空格。

stroke-dasharray 属性可以做的东西还有很多很多。虽然我之前的示例是它只接受一组值作为参数,但是它也可以接受多组值,并使用逗号来分隔每一组值。

<svg width="600px" height="60px">
    <line x1="0" y1="20" x2="600" y2="20" stroke="#000" stroke-width="3" stroke-dasharray="10 4, 5 10, 1 1, 10 30" />
</svg>

虚线会根据不同组的划线长度和空格大小来绘制图案,然后一直重复,直到可放置图案的空间用完。在上面的示例中,我设置了最后一个空格大小为30px,方便我们查看图案的重复。

stroke-dashoffset 属性

最后一个属性是 stroke-dashoffset ,它可以让你设置需要图案延迟绘制的距离。它可以接受任何单位的值,同样的,如果使用的是百分比,就是相对于当前视图的百分比。

<svg width="600px" height="60px">
    <line x1="0" y1="20" x2="600" y2="20" stroke="#000" stroke-width="3" stroke-dasharray="10 4, 5 10, 1 1, 10 30" stroke-dashoffset="10" />
</svg>

再回去看看上一段内容。 stroke-dashoffset 属性的结果和我最初的期望完全不符。我的初衷是设置一个偏移量,将图案的绘制起点往后移。可是结果恰恰相反,偏移量是让图案往前移的。

这是应用了偏移量和没有应用偏移量的同一个图案,希望可视化的结果可以帮助大家理解。

图形和线条

在这篇文章的开头我提到你可以填充图形或者线条,这听起来可能有点怪怪的。你怎么可能填充线条呢?毕竟,它是由线条组成的。

除了容易混淆的nonzeroevenodd算法,你可能不需要我来帮你理解像矩形或者圆形这样的基础图形的填充和描边。描边是图形的轮廓,填充是轮廓之内的所有东西。

既然这样的话,那线条呢?大部分线条不会使用填充,你看到的大多是线条的描边。线条没有什么内部填充,但是如果它是折线的话,可能就可以被填充了。折线可以看成是由每条有端点的线段组成的多边形。

例如,下边图中的折线和多边形看起来完全一样。

<svg width="300px" height="200px">
  <polyline points="10 10, 50 50, 75 175, 175 150, 175 50, 225 75, 225 150, 300 150" fill="red" />
</svg>

<svg width="300px" height="200px">
  <polygon points="10 10, 50 50, 75 175, 175 150, 175 50, 225 75, 225 150, 300 150" fill="red" />
</svg>

但是如果你添加一个描边,你会看到多边形把整个图形的轮廓都用线条完整地从起点到终点绘制出来了,而折线则没有。尽管它们的填充是一样的。

<svg width="300px" height="200px">
  <polyline points="10 10, 50 50, 75 175, 175 150, 175 50, 225 75, 225 150, 300 150" fill="red" stroke="#000" stroke-width="5" />
</svg>
<svg width="300px" height="200px">
  <polygon points="10 10, 50 50, 75 175, 175 150, 175 50, 225 75, 225 150, 300 150" fill="red" stroke="#000" stroke-width="5" />
</svg>

SVG属性和CSS

对于这个系列中的大部分示例,我都在不同的SVG元素上设置了SVG的属性作为其元素属性。之前的文章中我也展示了如何在你的CSS文件中设置属性值。你可以在CSS中设置更多的SVG属性,虽然不是所有的属性都可以,但是至少填充和描边是没有问题的。

你可以添加内联CSS如下:

<svg width="300px" height="300px">
    <rect x="20" y="20" width="250px" height="125px" style="fill: teal; stroke: 5px;" />
</svg>

你也可以直接在你的CSS文件中设置样式。

<svg width="300px" height="300px">
  <rect class="example" x="20" y="20" width="250px" height="125px" />
</svg>

.example {
  fill: teal;
  stroke: red;
  stroke-width: 5px
}

记住,把填充设置为和背景颜色不同的颜色,设置strokestroke-width,而不是border-color或者border-width

很多其它的SVG属性都可以写成CSS属性,而不是把它们作为属性添加给某个SVG元素。W3C有在维护这样的一个列表——可以用CSS样式来写的各个SVG属性

总结思考

正如我希望你了解的,给基础图形和线条添加填充和描边非常容易。如果你曾使用过background-color属性以及[CSS的border属性](borders in CSS](http://www.vanseodesign.com/css/borders-rounded-corners/),这篇文章对你来说就基本是复习了。

我对填充规则的算法还是有点不明白,但是直接用这两种可能性来测试还是很简单的,看看哪一个能够让你看到你想要的结果就行。

填充和描边都可以设置不透明度,描边还提供了设置线条终点形状、以及线段交接处形状的属性。你还可以把实线描边换成虚线描边。

你现在已经掌握了足够的基础,可以创建简单的SVG了。你需要知道如何创建简单的图形(如矩形、圆形或者是用多边形建立的复杂的形状),并为它们添加填充和描边。类似的还有简单或复杂的线条。

这些是非常基础的东西,除了用颜色填充圆形和矩形,你还可以使用SVG做很多其它的事情。比如,相比一个固态填充,你可以使用渐变或图案来填充其它的SVG元素。

在我们讲到那里之前,我想先看看我讲解图形时提到的东西。我提到路径是更好的用来创建基础图形的另一种方法。接下来的几个星期我会讲解如何使用路径创建直线、曲线和图形。

本文根据@Steven Bradley的《SVG Basics—Fills And Strokes》所译,整个译文带有我们自己的理解与思想,如果译得不好或有不对之处还请同行朋友指点。如需转载此译文,需注明英文出处:http://www.vanseodesign.com/web-design/svg-fill-stroke/

彦子

在校学生,本科计算机专业。逗比一枚,热爱前端热爱生活,喜欢CSS喜欢JavaScript喜欢SVG,爱玩PS玩AI玩啊逗比的软件。努力向上,厚积薄发。

如需转载,烦请注明出处:https://www.fedev.cn/svg/svg-fill-stroke.htmlAir Jordan XIII Slippers