写在前面
之前有提到过SVG描边动画,可以实现很神奇的手写签名动画效果,当然,理论上可以用来实现任意不规则路径填充动画
在支持SVG的场景,可以考虑采用强大的SVG描边动画,能够实现一些incredible效果,在处理不规则描边、填充动画方面疗效确切
一.兼容性
SVG(Scalable Vector Graphics)是一种基于XML的标记语言,用来描述二维矢量图
基础兼容性(Can I use SVG):
桌面 [IE9+]
移动 [Android4.4+] [Android3-4.3]部分支持
SVG动画元素兼容性(Can I use SVG animation):
移动 [Android3+] iOS[6.1+]
在移动端早就可以随便玩了,比如用animateMotion
实现沿不规则路径运动效果
二.应用场景
1.icon
iconfont兼容性确实比SVG好,但有一些限制:
只支持font相关的CSS规则
浏览器对字体的优化(抗锯齿等等),导致不同浏览器下icon显示效果有差异
依赖字体文件,糟糕情况(下载失败,或者用户偏好自定义字体)下,会显示框框,甚至与emoji冲突
只能纯色或者渐变,而且大小定位受line-height
, vertical-align
, letter-spacing
等影响,实际尺寸可能存在偏差(很难对齐)
SVG icon的优势:
矢量图,随便缩放
可以控制icon不同部分的样式,描边颜色等等
实际尺寸精确,占据空间与SVG元素尺寸一致
糟糕情况下,可以用png做平滑fallback
关于SVG icon的更多信息,请查看:
2.动画
SVG结合animation能够实现很多神奇的效果:
不规则描边动画(手写签名)
填充动画(手绘)
不规则路径动画(让元素沿不规则路径运动)
一个印象深刻的SVG动画:Animated line drawing in SVG,更多SVG动画案例见30 Awesome SVG Animation For Your Inspiration
3.图表
一些很受欢迎的图表库都采用SVG来实现,例如d3
、google charts
等等
相比canvas
图表,SVG
图表在过渡动画方面有先天优势,能够实现很漂亮的过渡效果,例如D3 Tree
三.SVG元素
SVG有一套自己的元素定义(与HTML元素类似),用来描述二维图形。用svg
标签包裹起来,可以直接嵌入HTML中,例如:
<h3>svg demo</h3>
<svg width="300" height="200" xmlns="http://www.w3.org/2000/svg">
<rect x="10" y="10" width="30" height="30"></rect>
</svg>
<span>sibling</span>
显示30x30px
的黑方块,svg
元素尺寸为100x100px
,svg
元素默认display: inline
,所以”sibling”文本与黑方块并列
P.S.width, height, x, y
等属性不带单位的话,默认是px
,也可以带em, ex, in, cm, mm, pt, pc, %
等单位
SVG元素比较多,且与HTML元素有交集,见SVG element reference
1.形状元素
基本形状有6种:<circle>, <ellipse>, <line>, <polygon>, <polyline>, <rect>
,另外<path>
可以用来定义任意形状,包括4中基本形状
rect
<rect x="50" y="10" width="30" height="30" rx="5" ry="5"></rect>
其中rx, ry
用来定义圆角,分别表示四角的椭圆在x
轴、y
轴方向的半径。当然,用圆角画圆的技巧仍然适用:
<rect x="50" y="10" width="30" height="30" rx="50%" ry="50%"></rect>
x, y
表示左上角的坐标,坐标系与canvas 2d
相同,左上角为(0, 0)
circle
<circle cx="150" cy="25" r="15"></circle>
cx, cy
表示圆心位置
ellipse
<ellipse cx="200" cy="30" rx="25" ry="20"></ellipse>
rx, ry
分别表示x
轴方向半径和y
轴方向半径
line
<line x1="250" y1="10" x2="300" y2="30" style="stroke: black"></line>
注意,默认没有描边,看不见线,这里用stroke
设置描边颜色
polygon
<polygon points="60,50 100,70 100,110 60,130 20,110 20,70"></polygon>
给定一组点,画出闭合多边形
polyline
<polyline points="150,50 190,70 190,110 150,130 110,110 110,70" style="fill: none; stroke: black"></polyline>
与多边形类似,折线不自动连接首尾
注意,默认填充黑色且没有描边,与上例多边形没有任何区别,这里用fill
去掉填充色,用stroke
添上黑色描边
2.path
通用形状定义,可以用来实现上面提到的所有形状,例如:
<path d="M 10 10 L 100 10 L 100 80 Z" style="fill: orange; stroke: black; stroke-width: 1"></path>
一个带黑色描边用橘黄色填充的直角三角形,属性d
表示一系列路径描述,包含一些指令:
Moveto M提笔到
Lineto L画直线到
H画水平直线到
V画竖直直线到
Curveto C画三次贝塞尔曲线到(需要提供2个控制点)
S与上一条三次贝塞尔曲线连起来(只需要提供第二个控制点和终点,第一个控制点是上一条曲线的第二个控制点的对称点)
Q画二次贝塞尔曲线到(需要提供1个控制点)
T与上一条二次贝塞尔曲线连起来(只需要提供终点,控制点是上一条曲线控制点的对称点)
Arcto A画椭圆曲线到
ClosePath Z直线连接当前点和起点
注意,用Z/z
闭合路径,与手动L 起点
不同,因为闭合指令会让把线段端点拼接起来
各指令具体用法:
M x,y 绝对坐标
m dx,dy 相对坐标
L/l 同上
H/h 同上
V/v 同上
C/c c1x,c1y c2x,c2y x,y 控制点1 控制点2 终点
S/s cx,cy x,y 控制点2 终点
Q/q cx,cy x,y 控制点 终点
T/t x,y 终点
A rx,ry xAxisRotate LargeArcFlag,SweepFlag x,y
x,y方向半径 x轴与水平轴顺时针夹角 [1/0]大/小角度弧线 [1/0]顺/逆时针到终点 终点
Z/z 无参,Z和z没有区别
例如:
<!-- 矩形 -->
<path d="M 10 10 H 70 80 V 70 80 H 10 10 z" style="stroke: black"></path>
<!-- 三次贝塞尔曲线 -->
<path d="M 10 10 C 30 40 90 60 30 100 S 50 50 150 10 S 100 130 100 120" style="fill: none; stroke: black"></path>
P.S.关于d
属性的更多信息,请查看:
3.文本
<text x="100" y="40" dx="10" dy="10" text-anchor="middle" rotate="10 10" style="font-family: Consola monospace; font-size: 24px; stroke: skyblue; fill: pink;">
SVG text styling
</text>
x, y
,dx, dy
用于定位,前者绝对定位,后者相对自身偏移,text-anchor
用来定位文本(相对x, y
左/右/居中对齐)
注意:rotate
属性很神奇,与style="transform: rotate(10deg);"
整体旋转不同,rotate
属性是针对字符(glyph)的,可以传入一组值,按顺序分别作用于各个字符,所以可以用来实现类似于斜体的效果
P.S.关于rotate
属性的更多信息,请查看Chapter 11: Text
4.样式
除了CSS支持的样式属性,SVG还支持一些特有的,例如stroke
、fill
等等,常见的如下:
fill 填充色,文本颜色也由该属性控制
stroke 描边颜色
stroke-width 描边宽度
stroke-linecap 端点样式,圆角,直角等等,与canvas一致,butt | round | square
stroke-dasharray 虚线样式
也可以通过CSS选择器对SVG元素应用样式,例如:
<style>.line {stroke: red;}</style>
<svg>
<line class="line" x1="10" y1="10" x2="100" y2="80"></line>
</svg>
但SVG
里的style
元素与HTML的不同,上面的方式等价于:
<svg>
<style><![CDATA[
.newLine {stroke: red;}
]]></style>
<line class="newLine" x1="10" y1="10" x2="100" y2="80"></line>
</svg>
把样式规则用CDATA
包起来是为了避免XML解析出错:
Note how the CSS style sheet is placed within a CDATA construct (i.e., <![CDATA[ … ]]>). Placing internal CSS style sheets within CDATA blocks is sometimes necessary since CSS style sheets can include characters, such as “>”, which conflict with XML parsers. Even if a given style sheet does not use characters that conflict with XML parsing, it is highly recommended that internal style sheets be placed inside CDATA blocks.
(引自Styling-SVG 1.1(Second Edition))
5.marker
marker
标记能贴附在图形元素上,例如用marker来添箭头:
<defs>
<marker id="Triangle" viewBox="0 0 10 10" refX="1" refY="5" markerWidth="6" markerHeight="6" orient="auto">
<path d="M 0 0 L 10 5 L 0 10 z" />
</marker>
</defs>
<path d="M 10 10 C 50 80 40 20 120 50" fill="none" stroke="black" stroke-width="1" marker-end="url(#Triangle)"></path>
通过defs
来定义可复用的元素,通过id
来引用之前定义的marker
元素,url(#Triangle)
叫Functional IRI reference
这里定义了一个箭头,并添到路径曲线的终点处,可选位置为:
marker-start 起点
marker-mid 各个中间点
marker-end 终点
marker
各属性含义如下:
viewBox 坐标系区域
refX/Y 参照点,绘制时该点与端点重合
markerUnits 定义坐标系单位 userSpaceOnUse当前坐标系单位 | strokeWidth线宽(默认)
markerWidth/Height 标记宽高,默认值为3
orient 绘制方向,值为auto或角度值
默认markerUnits="strokeWidth"
根据图形线宽自适应marker
尺寸,如果markerUnits="userSpaceOnUse"
的话,指定marker
单位为当前坐标系单位,不会相对图形线宽调整
默认orient="auto"
自动计算朝向角度,曲线上的箭头指向斜率方向,非常精细自然
P.S.关于marker
的更多信息,请查看11 Painting: Filling, Stroking and Marker Symbols
6.滤镜
通过应用filter
来改变渲染效果,让显示效果更好。使用方式与marker
类似:
<defs>
<filter id="blur">
<feGaussianBlur in="SourceGraphic" stdDeviation="5"/>
</filter>
</defs>
<path d="M 10 20 C 50 80 40 20 120 60" fill="none" stroke="black" stroke-width="1" filter="url(#blur)"></path>
通过feGaussianBlur
元素定义高斯模糊滤镜(毛玻璃效果),并设置模糊程度参数stdDeviation
,in
用来设置应用滤镜的对象,这里SourceGraphic
表示原图,也可以只对alpha通道或者背景图片(应用滤镜的整片区域快照)应用
此外还支持阴影、光照、颜色等滤镜,具体信息请查看SVG element reference
7.渐变
支持线性渐变和放射性渐变,用法与marker
类似,例如:
<defs>
<linearGradient id="linear" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" stop-color="#000"/>
<stop offset="100%" stop-color="#fff"/>
</linearGradient>
<radialGradient id="radial">
<stop offset="10%" stop-color="#eee"/>
<stop offset="95%" stop-color="#ccc"/>
</radialGradient>
</defs>
<rect x="0" y="0" width="100%" height="50%" fill="url(#linear)"></rect>
<rect x="0" y="50%" width="100%" height="50%" fill="url(#radial)"></rect>
分别定义了纯黑到纯白的竖直线性渐变、中心亮周围渐暗的放射性渐变
四.在线Demo
上文提到的所有示例:http://www.ayqy.net/temp/svg/svg.html