背景
svg背景可以对照css的background学习,但是css对背景的控制更加精细,其实叫做svg背景并不准确,叫做svg图案应该更好,svg背景使用pattern元素,相当于css的background-image。例如如下代码:
<svg width="500" height="500">
<defs>
<pattern id="topson" x="0" y="0" width="20%" height="20%" patternUnits="objectBoundingBox">
<path d="M0 0 Q 20 5 10 10 T 20 20" style="stroke:rgb(34, 69, 223);fill:none"></path>
<path d="M 0 0 h 20 v 20 h -20 z" style="stroke:rgb(247, 89, 89);fill:none;"></path>
</pattern>
</defs>
<rect x="20" y="20" width="100" height="100" style="fill:url(#topson);stroke:black;"/>
<rect x="135" y="20" width="70" height="80" style="fill:url(#topson);stroke:black;"/>
<rect x="225" y="20" width="150" height="130" style="fill:url(#topson);stroke:black;"/>
</svg>
效果如下:
注意这里面的patternUnits属性,是用来控制渲染模式的,也就是说这个属性可以控制背景图案是以一定比例填充还是平铺。上面的例子是按照一定比例填充,由于宽度定义了20%,所以不论矩形的宽度多大,最多只能放置5个图案,如果想让图案平铺的话使用userSpaceOnUse属性值,并且不能再定义百分比。例如:
<svg width="500" height="500">
<defs>
<pattern id="topson" x="0" y="0" width="20" height="20" patternUnits="userSpaceOnUse">
<path d="M0 0 Q 20 5 10 10 T 20 20" style="stroke:rgb(34, 69, 223);fill:none"></path>
<path d="M 0 0 h 20 v 20 h -20 z" style="stroke:rgb(247, 89, 89);fill:none;"></path>
</pattern>
</defs>
<rect x="20" y="20" width="100" height="100" style="fill:url(#topson);stroke:black;"/>
<rect x="135" y="20" width="70" height="80" style="fill:url(#topson);stroke:black;"/>
<rect x="225" y="20" width="150" height="130" style="fill:url(#topson);stroke:black;"/>
</svg>
效果如下:
如果使用userSpaceOnUse的话在做图形位移动画的时候会有下面的效果:
可以看到只改变矩形的位置,矩形里面的pattern并不会随着改变,所以我认为svg这点的设计并不好,如果想让背景平铺,并且不随元素位置发生移动,使用svg结合css使用能达到预期效果
虽然css的background-image很强大了,对于比较复杂的背景还是建议引用svg文件。理由有两个
1.svg的图案是可以嵌套的,可以做出很多复杂背景,虽然项目中不常用。
2.可以在svg中加入动画让背景动起来,要比加入gif动图小的多。
一个简单的例子:
渐变
svg支持两种渐变:线性渐变和径向渐变,
css支持三种渐变:线性渐变和径向渐变和锥形渐变
可以看到css颜色渐变的种类是比svg齐全的,下面介绍svg渐变,顺带说一下css锥形渐变。
线性渐变
svg的线性渐变使用linearGradient元素,先看一个例子:
<svg width="500" height="500" viewBox="0 0 500 500" xmlns="http://www.w3.org/2000/svg" >
<defs>
<linearGradient id="line_gra">
<stop offset="0%" stop-color="#ff0000"></stop>
<stop offset="100%" stop-color="#00ff00"></stop>
</linearGradient>
</defs>
<rect x="20" y="20" width="300" height="50" stroke="black" fill="url(#line_gra)"></rect>
</svg>
这是一个简单的双色渐变,除了渐变颜色还可以控制渐变透明度例如:
<svg width="500" height="500" viewBox="0 0 500 500" xmlns="http://www.w3.org/2000/svg" >
<defs>
<linearGradient id="line_gra">
<stop offset="0%" stop-color="#ff0000" stop-opacity="1.0"></stop>
<stop offset="50%" stop-color="#00ff00" stop-opacity="0.1"></stop>
<stop offset="100%" stop-color="#0000ff" stop-opacity="1.0"></stop>
</linearGradient>
</defs>
<rect x="20" y="20" width="300" height="50" stroke="black" fill="url(#line_gra)"></rect>
</svg>
,
接下来就是控制渐变色的方向了,看下面的例子:
<svg width="500" height="500" viewBox="0 0 500 500" xmlns="http://www.w3.org/2000/svg" >
<defs>
<linearGradient id="line_gra">
<stop offset="0%" stop-color="#ff0000" stop-opacity="1.0"></stop>
<stop offset="50%" stop-color="#00ff00" stop-opacity="0.1"></stop>
<stop offset="100%" stop-color="#0000ff" stop-opacity="1.0"></stop>
</linearGradient>
<linearGradient id="to_down" x1="0%" y1="0%" x2="100%" y2="100%" xlink:href="#line_gra"></linearGradient>
</defs>
<rect x="20" y="20" width="300" height="50" stroke="black" fill="url(#to_down)"></rect>
</svg>
我们可以控制渐变的其实位置,但是如果我们的渐变不是从0%到100%,而是从30%到60%,那么0%-30%的部分和60%-100%的部分如何渲染呢?看一下例子:
<svg width="500" height="500" viewBox="0 0 500 500" xmlns="http://www.w3.org/2000/svg" >
<defs>
<linearGradient id="line_gra" x1="30%" y1="50%" x2="60%" y2="50%">
<stop offset="0%" stop-color="#ff0000"></stop>
<stop offset="50%" stop-color="#00ff00"></stop>
<stop offset="100%" stop-color="#0000ff"></stop>
</linearGradient>
</defs>
<rect x="20" y="20" width="300" height="50" stroke="black" fill="url(#line_gra)"></rect>
</svg>
可以看到另外两部分是按照起始或者结束的值渲染的,这个渲染效果和css是一致的,但是svg的一个属性spreadMethod可以定义超出部分的渲染模式。有pad/repeat/reflect三种模式:
pad是默认模式,就是按照起点和终点扩展。
repeat:重复起点终点充满整个对象
reflect:渐变会按照起点终点排列来充满对象
概念有点不太好理解,不如直接上图,
,
css里对这方面的控制不如svg。css中有个repeating-linear-gradient,值用来控制重复效果同repeat,但是没有提供reflect模式。
径向渐变
径向渐变,表示的是圆形路径从圆心向外展开,svg中的语法和线性渐变基本相同,使用radialGradient元素,例如:
<svg width="500" height="500" viewBox="0 0 500 500" xmlns="http://www.w3.org/2000/svg" >
<defs>
<radialGradient id="radia_gra" cx="0%" cy="0%" r="80%">
<stop offset="0%" stop-color="#ff0000"></stop>
<stop offset="50%" stop-color="#00ff00"></stop>
<stop offset="100%" stop-color="#0000ff"></stop>
</radialGradient>
<radialGradient id="repeated" xlink:href="#line_gra" spreadMethod="repeat"></radialGradient>
</defs>
<rect x="20" y="20" width="300" height="300" stroke="black" fill="url(#radia_gra)"></rect>
</svg>
cx,cy表示圆心位置,r表示渐变半径,关于半径说明一下,假设将半径设置为100%,渐变半径是矩形的边长,如果想让渐变充满整个矩形,可以将半径设置为2的平方根,就是1.41即141%。
我们还可以修改圆形的渐变圆心,通过fx,fy,修改例如:
<svg width="500" height="500" viewBox="0 0 500 500" xmlns="http://www.w3.org/2000/svg" >
<defs>
<radialGradient id="radia_gra" cx="0%" cy="0%" r="80%" fx="50%" fy="50%">
<stop offset="0%" stop-color="#ff0000"></stop>
<stop offset="50%" stop-color="#00ff00"></stop>
<stop offset="100%" stop-color="#0000ff"></stop>
</radialGradient>
<radialGradient id="repeated" xlink:href="#line_gra" spreadMethod="repeat"></radialGradient>
</defs>
<rect x="20" y="20" width="300" height="300" stroke="black" fill="url(#radia_gra)"></rect>
</svg>
有兴趣的同学可以尝试一下r<fx/fy的情况,还是比较有意思的。可以看到像是一个光照的效果,径向渐变的渲染模式spreadMethod和线性渐变是一样的,有兴趣的同学可以自己尝试。不再重复。
css锥形渐变
css提供了另外一种渐变,锥形渐变,简单介绍一下,说明css和svg的区别,看如下代码:
.coneGrid{
width:300px;
height:300px;
background-image: conic-gradient(from 45deg at 40% 40%,rgb(209, 57, 57), rgb(56, 214, 16));
border-radius: 50%;
}
这种渐变可以做像是雷达扫描的效果。
剪切
svg剪切要剪掉图像的一部分,svg使用clipth元素,css也支持clip-path,我在前面的文章有过介绍,path的语法是一样的。下面先看一个简单的svg的剪切例子:
<svg width="500" height="500" viewBox="0 0 500 500" xmlns="http://www.w3.org/2000/svg" >
<defs>
<clipPath id="circleClip">
<circle cx="25" cy="75" r="200" stroke="red" fill="transparent" stroke-width="5"/>
</clipPath>
<radialGradient id="radia_gra" cx="0%" cy="0%" r="141%" fx="40%" fy="40%">
<stop offset="0%" stop-color="#ff0000"></stop>
<stop offset="50%" stop-color="#00ff00"></stop>
<stop offset="100%" stop-color="#0000ff"></stop>
</radialGradient>
</defs>
<rect x="20" y="20" width="300" height="300" stroke="black" fill="url(#radia_gra)" clip-path="url(#circleClip)"></rect>
</svg>
clipPath里面可以有多个路径,甚至可以是文字,
<svg width="500" height="500" viewBox="0 0 500 500" xmlns="http://www.w3.org/2000/svg" >
<defs>
<clipPath id="circleClip">
<circle cx="25" cy="75" r="200" stroke="red" fill="transparent" stroke-width="5"/>
<text x="180" y="200" style="font-family: 'Courier New', Courier, monospace;font-size: 48pt;fill:none;stroke:black;font-weight: bolder;">clip</text>
</clipPath>
<radialGradient id="radia_gra" cx="0%" cy="0%" r="141%" fx="40%" fy="40%">
<stop offset="0%" stop-color="#ff0000"></stop>
<stop offset="50%" stop-color="#00ff00"></stop>
<stop offset="100%" stop-color="#0000ff"></stop>
</radialGradient>
</defs>
<rect x="20" y="20" width="300" height="300" stroke="black" fill="url(#radia_gra)" clip-path="url(#circleClip)"></rect>
</svg>
这就很容易联想到css3的-webkit-background-clip:text属性,做出炫酷的文字效果。当然clipPath里面还可以使用path路径,不过路径是需要闭合的。
蒙层
svg的蒙层是一个不太好理解的特性,可以理解为给元素一个透明度,但是svg并没有直接取蒙层元素的透明度,而是使用下面的计算公式:
(0.2125red + 0.7154green + 0.0721*blue)*opacity
将蒙层的红绿蓝色值都使用上了。
下面我们详细探究一下,看如下例子:
<svg width="500" height="500" viewBox="0 0 500 500" xmlns="http://www.w3.org/2000/svg" >
<defs>
<mask id="remark" x="0" y="0" width="1" height="1" maskContentUnits="objectBoundingBox">
<rect x="0" y="0" width="1" height="1" fill="#ff0000"></rect>
</mask>
<mask id="grmark" x="0" y="0" width="1" height="1" maskContentUnits="objectBoundingBox">
<rect x="0" y="0" width="1" height="1" fill="#00ff00"></rect>
</mask>
<mask id="blmark" x="0" y="0" width="1" height="1" maskContentUnits="objectBoundingBox">
<rect x="0" y="0" width="1" height="1" fill="#0000ff"></rect>
</mask>
<mask id="whitemark" x="0" y="0" width="1" height="1" maskContentUnits="objectBoundingBox">
<rect x="0" y="0" width="1" height="1" fill="#ffffff"></rect>
</mask>
</defs>
<g style="mask:url(#remark);font-size: 28px;text-anchor:middle">
<circle cx="35" cy="115" r="30" fill="#ff0000"/>
<text x="35" y="220">red</text>
</g>
<circle cx="35" cy="45" r="30" fill="#f00" fill-opacity="0.2125"/>
<g style="mask:url(#grmark);font-size: 28px;text-anchor:middle">
<circle cx="135" cy="115" r="30" fill="#ff0000"/>
<text x="135" y="220">green</text>
</g>
<circle cx="135" cy="45" r="30" fill="#ff0000"/>
<g style="mask:url(#blmark);font-size: 28px;text-anchor:middle">
<circle cx="235" cy="115" r="30" fill="#ff0000"/>
<text x="235" y="220">blue</text>
</g>
<circle cx="235" cy="45" r="30" fill="#ff0000"/>
<g style="mask:url(#whitemark);font-size: 28px;text-anchor:middle">
<circle cx="335" cy="115" r="30" fill="#ff0000"/>
<text x="335" y="220">white</text>
</g>
<circle cx="335" cy="45" r="30" fill="#ff0000"/>
</svg>
效果如下:
在计算的过程中0-255会映射到0-1上进行计算。
如果只是简单的给元素加上透明度,是没必要使用蒙层的,关键是我们可以使用蒙层结合渐变色,做出同一个元素不同部分透明度不同的效果,这是比较有用的。下一节我们会使用蒙层,剪切,渐变做出一些不错的效果。