SVG基础知识

写在前面

之前有提到过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来实现,例如d3google 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元素尺寸为100x100pxsvg元素默认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, ydx, dy用于定位,前者绝对定位,后者相对自身偏移,text-anchor用来定位文本(相对x, y左/右/居中对齐)

注意:rotate属性很神奇,与style="transform: rotate(10deg);"整体旋转不同,rotate属性是针对字符(glyph)的,可以传入一组值,按顺序分别作用于各个字符,所以可以用来实现类似于斜体的效果

P.S.关于rotate属性的更多信息,请查看Chapter 11: Text

4.样式

除了CSS支持的样式属性,SVG还支持一些特有的,例如strokefill等等,常见的如下:

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元素定义高斯模糊滤镜(毛玻璃效果),并设置模糊程度参数stdDeviationin用来设置应用滤镜的对象,这里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

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*

code