svg 进阶
填充和边框
svg 可以使用多种方法来着色,指定对象的属性使用内联 css 样式、内嵌 css 样式,或者使用外部 css 样式文件
fill 和 stroke 属性
fill 属性设置对象内部的颜色
stroke 属性则会设置对象的线条颜色
可以使用 HTML 中的 css 颜色命名方案,如颜色名 red、十六进制值、rgba 值等等
<rect x="10" y="10" width="100" height="100" stroke="blue" fill="purple" fill-opacity="0.5" stroke-opacity="0.8"/>
除此之外,你还可以分别定义填充色和边框色的不透明度,属性 fill-opacity 控制填充色的透明度,属性 stroke-opacity 控制边框线条的透明度
描边
控制绘制描边的方式
<?xml version="1.0" standalone="no"?>
<svg width="160" height="140" xmlns="http://www.w3.org/2000/svg" version="1.1">
<line x1="40" x2="120" y1="20" y2="20" stroke="black" stroke-width="20" stroke-linecap="butt"/>
<line x1="40" x2="120" y1="60" y2="60" stroke="black" stroke-width="20" stroke-linecap="square"/>
<line x1="40" x2="120" y1="100" y2="100" stroke="black" stroke-width="20" stroke-linecap="round"/>
</svg>
stroke-linecap 控制边框终点的形状
- butt 直角边结束线段
- square 效果跟 butt 差不多,不过会稍微超出实际路径的范围,超过的大小由 stroke-width 来控制
- round 圆角结束线段,圆角的半径也是由 stroke-width 来控制
stroke-linejoin 控制两条描边之间,用什么方式连接
<?xml version="1.0" standalone="no"?>
<svg width="160" height="280" xmlns="http://www.w3.org/2000/svg" version="1.1">
<polyline points="40 60 80 20 120 60" stroke="black" stroke-width="20"
stroke-linecap="butt" fill="none" stroke-linejoin="miter"/>
<polyline points="40 140 80 100 120 140" stroke="black" stroke-width="20"
stroke-linecap="round" fill="none" stroke-linejoin="round"/>
<polyline points="40 220 80 180 120 220" stroke="black" stroke-width="20"
stroke-linecap="square" fill="none" stroke-linejoin="bevel"/>
</svg>
- miter 方形画笔在连接处形成尖角
- round 表示用圆角连接
- bevel 表示连接处形成一个斜接
stroke-dasharray 将虚线类型应用在描边上
<?xml version="1.0" standalone="no"?>
<svg width="200" height="150" xmlns="http://www.w3.org/2000/svg" version="1.1">
<path d="M 10 75 Q 50 10 100 75 T 190 75" stroke="black"
stroke-linecap="round" stroke-dasharray="5,10,5" fill="none"/>
<path d="M 10 75 L 190 75" stroke="red"
stroke-linecap="round" stroke-width="1" stroke-dasharray="5,5" fill="none"/>
</svg>
参数是一组用逗号分隔的数字形成的数列。每一组的数字,第一个数字代表的是填色区域长度,第二个数字代表的是非填色区域的长度(可以理解为间距),如果一组数字中的个数是单数的话,会先循环两次变成偶数个,然后继续绘制
使用 css
可以使用 css 来样式化填充和描边。语法跟 html 里面使用 css 一样,只不过需要把 backgound、border 改成 fill 和 stroke。
注意,不是所有的属性都可以用 css 来设置。像 width、height,以及路径的命令等等,都不能用 css 设置
利用 css 的 style 属性插入到元素的行间
<rect x="10" height="180" y="10" width="180" style="stroke: black; fill: red;"/>
或者,可以移入到一个特殊的样式部分,包含在一个叫做 <defs>
的区域
<defs>
表示定义,可以定义一些不会在 svg 图形中出现,但是可以被其他元素引用的元素
<?xml version="1.0" standalone="no"?>
<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg" version="1.1">
<defs>
<style><![CDATA[
#MyRect {
stroke: black;
fill: red;
}
]]></style>
</defs>
<rect x="10" height="180" y="10" width="180" id="MyRect"/>
</svg>
同样地,你可以定义一个外部的样式表
<?xml version="1.0" standalone="no"?>
<?xml-stylesheet type="text/css" href="style.css"?>
<svg width="200" height="150" xmlns="http://www.w3.org/2000/svg" version="1.1">
<rect height="10" width="10" id="MyRect"/>
</svg>
渐变
并非只能简单地填充和描边,还可以创建并在填充和描边上应用渐变色
有两种渐变,一种是线性渐变,一种是径向渐变,必须给渐变内容指定一个 id 属性,否则文档内的其他元素就不能引用它
线性渐变
在 defs 元素内部定义一个 <linearGradient>
元素
<svg width="120" height="240" version="1.1" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="Gradient1">
<stop class="stop1" offset="0%" />
<stop class="stop2" offset="50%" />
<stop class="stop3" offset="100%" />
</linearGradient>
<linearGradient id="Gradient2" x1="0" x2="0" y1="0" y2="1">
<stop offset="0%" stop-color="red" />
<stop offset="50%" stop-color="black" stop-opacity="0" />
<stop offset="100%" stop-color="blue" />
</linearGradient>
<style type="text/css">
<![CDATA[
#rect1 { fill: url(#Gradient1); }
.stop1 { stop-color: red; }
.stop2 { stop-color: black; stop-opacity: 0; }
.stop3 { stop-color: blue; }
]]>
</style>
</defs>
<rect id="rect1" x="10" y="10" rx="15" ry="15" width="100" height="100" />
<rect
x="10"
y="120"
rx="15"
ry="15"
width="100"
height="100"
fill="url(#Gradient2)" />
</svg>
线性渐变内部有几个 <stop>
结点,这些结点通过指定位置的 offset 属性和 stop-color 属性来说明渐变在特定位置上应该是什么颜色;offset 偏移量始终应该以 0 (0%) 开始 到 1 (100%)结束,stop-opacity 可以设置某个位置的透明度
使用渐变,可以在一个对象属性的 fill 或者属性 stroke 中引用它,与 css 使用 url 应用元素的方法一致
fill: url(#gradient1);
渐变的方向可以使用两个点来控制,分别是 x1、y1、x2、y2
下面是创建一个垂直渐变的例子
<linearGradient id="Gradient2" x1="0" x2="0" y1="0" y2="1"></linearGradient>
径向渐变
使用 <radioGradient>
元素来创建径向渐变
<?xml version="1.0" standalone="no"?>
<svg width="120" height="240" version="1.1" xmlns="http://www.w3.org/2000/svg">
<defs>
<radialGradient id="RadialGradient1">
<stop offset="0%" stop-color="red" />
<stop offset="100%" stop-color="blue" />
</radialGradient>
<radialGradient id="RadialGradient2" cx="0.25" cy="0.25" r="0.25">
<stop offset="0%" stop-color="red" />
<stop offset="100%" stop-color="blue" />
</radialGradient>
</defs>
<rect
x="10"
y="10"
rx="15"
ry="15"
width="100"
height="100"
fill="url(#RadialGradient1)" />
<rect
x="10"
y="120"
rx="15"
ry="15"
width="100"
height="100"
fill="url(#RadialGradient2)" />
</svg>
对象中间是红色的,且向着边缘渐渐变成蓝色。跟线性渐变一样,径向渐变也是通过两个点来确认边缘位置,cx cy 为第一个点,定义了渐变结束围绕的圆环,第二个点称为焦点,由 fx 和 fy 属性定义
spreadMethod 属性,控制当渐变到达终点的行为
- pad 最终的偏移颜色将用于填充对象剩下的空间
- reflect 会让渐变一直持续下去,是反向渐变
- repeat 跳回最初的颜色继续渐变
两种渐变都有一个叫做 gradientUnits(渐变单元)的属性,它描述了用来描述渐变的大小和方向的单元系统。该属性有两个值:userSpaceOnUse 、objectBoundingBox。默认值为 objectBoundingBox,我们目前看到的效果都是在这种系统下的,它大体上定义了对象的渐变大小范围,所以你只要指定从 0 到 1 的坐标值,渐变就会自动的缩放到对象相同大小。userSpaceOnUse 使用绝对单元,所以你必须知道对象的位置,并将渐变放在同样地位置上。上例中的 radialGradient 需要被重写成:
<radialGradient
id="Gradient"
cx="60"
cy="60"
r="50"
fx="35"
fy="35"
gradientUnits="userSpaceOnUse"></radialGradient>
patterns
图案,功能非常强大,作用是 svg 填充
<patterns>
同样要放到 defs 内部
<?xml version="1.0" standalone="no"?>
<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg" version="1.1">
<defs>
<linearGradient id="Gradient1">
<stop offset="5%" stop-color="white" />
<stop offset="95%" stop-color="blue" />
</linearGradient>
<linearGradient id="Gradient2" x1="0" x2="0" y1="0" y2="1">
<stop offset="5%" stop-color="red" />
<stop offset="95%" stop-color="orange" />
</linearGradient>
<pattern id="Pattern" x="0" y="0" width=".25" height=".25">
<rect x="0" y="0" width="50" height="50" fill="skyblue" />
<rect x="0" y="0" width="25" height="25" fill="url(#Gradient2)" />
<circle
cx="25"
cy="25"
r="20"
fill="url(#Gradient1)"
fill-opacity="0.5" />
</pattern>
</defs>
<rect
fill="url(#Pattern)"
stroke="black"
x="0"
y="0"
width="200"
height="200" />
</svg>
在 pattern 元素内部,你可以定义任何之前包含过的其他基本形状,并且每个形状都可以使用之前学习过的任何样式样式化,包括渐变和半透明
关于 pattern 容易混淆的事是,pattern 定义了一个单元系统以及他们的大小。上例中,我们在 pattern 元素上定义了width和height属性,用于描述在重复下一个图案之前应该跨过多远。如果你想要在绘制时偏移矩形的开始点,也可以使用 x 和 y 属性,原因如下。
就像前面使用了gradientUnits属性,同样的pattern也有一个属性patternUnits用于描述我们使用的属性单元。这同之前使用的objectBoundingBox默认值一样,所以当一个值为 1 时,它被缩放到应用 pattern 对象的宽高值。因此,我们希望 pattern 垂直和水平的重复 4 次,所以宽高被设置位 0.25,这一位置 pattern 的宽高仅为总外框大小的 0.25。
与渐变不同,pattern 有第二个属性patternContentUnits,它描述了pattern元素基于基本形状使用的单元系统,这个属性默认值为userSpaceOnUse,与patternUnits属性相反,这意味着除非你至少指定其中一个属性值(patternContentUnits或patternUnits),否则在pattern中绘制的形状将与pattern元素使用的坐标系不同,当你手写这部分时会容易混淆。为了使上例生效,我们必须考虑我们的边框(200 像素)大小和我们实际希望pattern垂直和水平重复 4 次的需求。这意味着每个 pattern 单元应该是 50x50的方形,pattern 中的两个矩形和圆形的大小会被缩放适应到一个 50x50 的边框里,任何我们绘制在边框外的内容都不会显示。因为我们希望 pattern 从边框的左上角里开始,所以 pattern 也必须偏移 10 像素,也就是 pattern 的 x 和 y 属性需要调整为 10/200=0.05。