SVG可缩放矢量图形(Scalable Vector Graphics)这项技术,现在越来越让大家熟知,在h5的移动端应用使用也越来越广泛了, 下面让我分享给大家svg学习的经验。
HTML体系中,最常用的绘制矢量图的技术是SVG和HTML5新增加的canvas元素。这两种技术都支持绘制矢量图和光栅图。
一、什么是svg?
Graphics)是基于可扩展标记语言(XML),用于描述二维矢量图形的一种图形格式。SVG是W3C在2000年8月制定的一种新的二维矢量图形格式,也是规范中的网络矢量图形标准。SVG严格遵从XML语法,并用文本格式的描述性语言来描述图像内容,因此是一种和图像分辨率无关的矢量图形格式。
特征:
SVG 指可伸缩矢量图形 (Scalable Vector Graphics)
SVG 用来定义用于网络的基于矢量的图形
SVG 使用 XML 格式定义图形
SVG 图像在放大或改变尺寸的情况下其图形质量不会有所损失
SVG 是万维网联盟的标准
SVG 与诸如 DOM 和 XSL 之类的 W3C 标准是一个整体
与其他图像格式相比,使用 SVG 的优势在于:
SVG 可被非常多的工具读取和修改(比如记事本)
SVG 与 JPEG 和 GIF 图像比起来,尺寸更小,且可压缩性更强。
SVG 是可伸缩的
SVG 图像可在任何的分辨率下被高质量地打印
SVG 可在图像质量不下降的情况下被放大
SVG 图像中的文本是可选的,同时也是可搜索的(很适合制作地图)
SVG 可以与 Java 技术一起运行
SVG 是开放的标准
SVG 文件是纯粹的 XML
在兼容方面,chrome、foxfire、ie9及以上浏览器支持,但是SVG SMIL动画 IE浏览器(包括IE11)整体不支持(但对于移动端来说呢,基本支持)。
注意:SVG是以XML定义的,所以是大小写敏感的,这点与HTML不一样。
二、SVG的呈现方式
对于直接支持SVG的浏览器,SVG主要采用两面两种呈现的方式。
内联到HTML
SVG是标准的HTML元素,直接写到HTML中就可以了,看下面的例子:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html> <html> <head> <!-- <meta content="text/html; charset=utf-8" http-equiv="Content-Type" /> --> <title> My First SVG Page</title> </head> <body> <svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="200px" height="200px"> <rect x="0" y="0" width="100%" height="100%" fill="none" stroke="black"/> <circle cx="100" cy="100" r="50" style="stroke: black; fill: red;"/> </svg> </body> </html>
请注意开头的部分xml声明,与svg的命名空间xmlns、版本version等部分,主要是考虑兼容性的问题;这些部分在HTML5中基本都可以不用写了(写不写还是自己瞧着办吧)。
独立SVG文件
独立SVG指的是通过使用svg文件扩展名来提供向量图形文件格式。在浏览器中嵌入这个svg文件就可以使用了。
1.独立的SVG文件/页面,定义的模板基本就像下面的一样:
<svg width="100%" height="100%"> <!-- SVG markup here. --> <circle cx="100" cy="100" r="50" style="stroke: black; fill: red;"/> </svg>
把这样的文本文件保存成以svg为扩展名的文件,例如sun.svg,这样的文件可以直接用浏览器打开浏览,也可以作为引用嵌入到别的页面中。
2.HTML引用外部的SVG文件,可以使用<embed> <object> <iframe> 引入
语法:<embed>
<embed src="rect.svg" width="300" height="100" type="image/svg+xml" pluginspage="http://www.adobe.com/svg/viewer/install/" />
语法:<object>
<object data="rect.svg" width="300" height="100" type="image/svg+xml" codebase="http://www.adobe.com/svg/viewer/install/" />
语法:<iframe>
<iframe src="rect.svg" width="300" height="100"> </iframe>
三、SVG的渲染顺序
SVG是严格按照定义元素的顺序来渲染的,这个与HTML靠z-index值来控制分层不一样。在SVG中,写在前面的元素先被渲染,写在后面的元素后被渲染。后渲染的元素会覆盖前面的元素,虽然有时候受透明度影响,看起来不是被覆盖的,但是SVG确实是严格按照先后顺序来渲染的。
四、SVG的文档结构
SVG文档的元素基本可以分为以下几类:
- 图形元素:circle, ellipse, line, path, polygon, polyline, rect;
- 解释元素:desc, metadata, title;
- 结构元素:defs, g, svg, symbol, use;
- 渐变元素:linearGradient, radialGradient;
- 动画元素:animate, animateColor, animateMotion, animateTransform, set;
- 其他元素:a,altGlyphDef,clipPath,color-profile,cursor,filter,font,font-face,foreignObject,image,marker,mask,pattern,script,style,switch,text,view等。
视窗 - svg元素
可以在svg元素中以任何顺序放置任何的其他元素,包括嵌套svg元素。
svg元素支持的属性常用的也就是id,class,x,y,width,height,viewBox,preserveAspectRatio,以及fill和stroke的相关属性。
svg元素支持的事件也是常用的onload, onmouseover, onmousemove, onmousedown, onmouseup, onclick, onfocusin, onfocusout, onresize, onscroll, onunload等。svg元素就不多说了,完整的属性和事件列表参看后面的官方文档。
图形元素:
SVG 有一些预定义的形状元素,可被开发者使用和操作:
- 矩形 <rect>
- 圆形 <circle>
- 椭圆 <ellipse>
- 线 <line>
- 折线 <polyline>
- 多边形 <polygon>
- 路径 <path>
具体的我说一下path的用法,其他的都比较好理解:
路径 - path元素
这个是最通用,最强力的元素了;使用这个元素你可以实现任何其他的图形,不仅包括上面这些基本形状,也可以实现像贝塞尔曲线那样的复杂形状;此外,使用path可以实现平滑的过渡线段,虽然也可以使用polyline来实现这种效果,但是需要提供的点很多,而且放大了效果也不好。这个元素控制位置和形状的只有一个参数:
d:一系列绘制指令和绘制参数(点)组合成。
绘制指令分为绝对坐标指令和相对坐标指令两种,这两种指令使用的字母是一样的,就是大小写不一样,绝对指令使用大写字母,坐标也是绝对坐标;相对指令使用对应的小写字母,点的坐标表示的都是偏移量。
绝对坐标绘制指令
这组指令的参数代表的是绝对坐标。假设当前画笔所在的位置为(x0,y0),则下面的绝对坐标指令代表的含义如下所示:
指令 |
参数 |
说明 |
M |
x y |
将画笔移动到点(x,y) |
L |
x y |
画笔从当前的点绘制线段到点(x,y) |
H |
x |
画笔从当前的点绘制水平线段到点(x,y0) |
V |
y |
画笔从当前的点绘制竖直线段到点(x0,y) |
A |
rx ry x-axis-rotation large-arc-flag sweep-flag x y |
画笔从当前的点绘制一段圆弧到点(x,y) |
C |
x1 y1, x2 y2, x y |
画笔从当前的点绘制一段三次贝塞尔曲线到点(x,y) |
S |
x2 y2, x y |
特殊版本的三次贝塞尔曲线(省略第一个控制点) |
Q |
x1 y1, x y |
绘制二次贝塞尔曲线到点(x,y) |
T |
x y |
特殊版本的二次贝塞尔曲线(省略控制点) |
Z |
无参数 |
绘制闭合图形,如果d属性不指定Z命令,则绘制线段,而不是封闭图形。 |
移动画笔指令M,画直线指令:L,H,V,闭合指令Z都比较简单。例子:
<svg width="200" height="150"> <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="20" fill="none"/> </svg>
解释性元素 - desc元素与title元素(此元素主要是做辅助,不会显示)
每个容器元素(可以包含其他容器元素或者图形元素的元素,例如:a,defs,glyph,g,marker,mask,missing-glyph,pattern,svg,switch和symbol)和图形元素都可以包含desc和title元素,这两个元素都是辅助性的元素,用于解释相关情境;它们的内容都是文本。当SVG文档被渲染的时候,这2个元素不会被渲染到图形中。这个2个元素之间差别不是太大,title在有些实现中是作为提示信息出现的,所以通常title是放到父元素的第一个位置上。
结构元素
组合 - g元素
g元素是一种容器,它组合一组相关的图形元素成为一个整体;这样,我们就可以对这个整体进行操作。这个元素通常可以和desc和title元素配合使用,提供文档的结构信息。结构良好的文档通常可读性和渲染效率都不错。看一个小例子:
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="5cm" height="5cm"> <desc>Two groups, each of two rectangles</desc> <g id="group1" fill="red"> <rect x="1cm" y="1cm" width="1cm" height="1cm"/> <rect x="3cm" y="1cm" width="1cm" height="1cm"/> </g> <g id="group2" fill="blue"> <rect x="1cm" y="3cm" width="1cm" height="1cm"/> <rect x="3cm" y="3cm" width="1cm" height="1cm"/> </g> <!-- Show outline of canvas using ‘rect‘ element --> <rect x=".01cm" y=".01cm" width="4.98cm" height="4.98cm" fill="none" stroke="blue" stroke-width=".02cm"/> </svg>
注意几点:
1. xmlns="http://www.w3.org/2000/svg"表明了整个svg元素默认的命名空间是svg。这个在无歧义的时候可以省略。这里由于svg文档是一个XML文档,XML命名空间的相关规则这里都是适用的。例如可以给svg显示的指定命名空间,给命名空间提供别名等。
2. g元素是可以嵌套的。
3. 组合起来的图形元素就和单个的元素一样,可以给id值,这样,需要的时候(例如动画和重用一组元素)只用引用这个id值就可以了。
4. 组合一组图形元素可以统一设置这组元素的相关属性(fill,stroke,transform等),这也是使用组合的一种场景。
模板 - symbol元素
symbol元素用于定义图形模板(模板可以包含很多图形),这个模板可以被use元素实例化。模板的功能与g元素很相似,都是提供一组图形对象,但是也有一些区别。与g元素不同的地方是:
1.symbol元素本身是不会被渲染的,只有symbol模板的实例会被渲染。
2.symbol元素可以拥有属性viewBox和preserveAspectRatio,这些允许symbol缩放图形元素。
从渲染角度来说,与symbol元素相似的元素是marker(定义箭头和标号)和pattern(定义颜色)元素;这些元素不会直接被渲染;他们的使用方式基本都是由use元素去实例化。正是这个原因,对于symbol来说,‘display‘属性是没有意义的。
下面这个修改过的代码显示了symbol的使用方式:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="5cm" height="5cm"> <desc>Two groups, each of two rectangles</desc> <symbol id="group1" fill="red"> <rect x="1cm" y="1cm" width="1cm" height="1cm"/> <rect x="3cm" y="1cm" width="1cm" height="1cm"/> </symbol> <g id="group2" fill="blue"> <rect x="1cm" y="3cm" width="1cm" height="1cm"/> <rect x="3cm" y="3cm" width="1cm" height="1cm"/> </g> <use xlink:href="#group1" target="_blank" rel="nofollow"> <!-- Show outline of canvas using ‘rect‘ element --> <rect x=".02cm" y=".02cm" width="4.96cm" height="4.96cm" fill="none" stroke="blue" stroke-width=".02cm"/> </svg>
定义 - defs元素
SVG允许定义一组对象,然后重用这组对象(注意,不仅仅是图形对象)。最常见的例子如定义渐变色,然后再其他的图形对象中赋给fill属性。渐变色定义的时候是不会渲染的,所以这类型的对象可以放到任何地方。重用对于图形对象中也是经常存在的,而且我们也不希望定义的时候直接渲染,而是想在引用的地方渲染,这个可以用defs元素实现。
通常情况下,推荐的做法是:只要有可能,就把被引用的对象放到defs元素中。这些对象通常是:altGlyphDef,clipPath,cursor,filter, marker,mask,pattern,linearGradient,radialGradient,symbol和图形对象等。把这些对象定义在defs元素中很容易理解,所以就提高了可访问性。
其实作为容器对象的g元素、symbol元素、defs元素都不同程度上提供了重用的作用,只不过每个元素的特性可能少许不同:比如g元素是直接渲染的,symbol和defs不会直接渲染,symbol含有viewBox属性,会创建新的视窗。
通常都会给在defs中定义的元素赋予id属性,并在用到的地方直接使用。根据元素的不同,这些定义可以用到不同地方,比如下面的渐进色作为属性来使用了:
<svg width="8cm" height="3cm" xmlns="http://www.w3.org/2000/svg" version="1.1"> <desc>Local URI references within ancestor‘s ‘defs‘ element.</desc> <defs> <linearGradient id="Gradient01"> <stop offset="20%" stop-color="#39F" /> <stop offset="90%" stop-color="#F3F" /> </linearGradient> </defs> <rect x="1cm" y="1cm" width="6cm" height="1cm" fill="url(#Gradient01)" /> </svg>
图形相关元素的定义可以用use元素链接到文档。例如:
<svg width="10cm" height="3cm" viewBox="0 0 100 30" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <desc>Example Use01 - Simple case of ‘use‘ on a ‘rect‘</desc> <defs> <rect id="MyRect" width="60" height="10"/> </defs> <rect x=".1" y=".1" width="99.8" height="29.8" fill="none" stroke="blue" stroke-width=".2" /> <use x="20" y="10" xlink:href="#MyRect" /> </svg>
在这里请注意xlink名称空间的使用。尽管大多数查看器没有它也将正确显示这一项,但为了保持一致,xlink名称空间应该在<svg></svg>元素上定义。
动画元素
SVG提供了下列动画元素:
1. animate元素
这个是最基本的动画元素,可以直接为相关属性提供不同时间点的值。
2. set元素
这个是animate元素的简写形式,支持所有的属性类型,尤其是当对非数字型的属性(例如visibility)进行动画时很方便。set元素是非增量的,相关的属性对之无效。 to指定的动画结束值类型一定要符合属性的取值类型。
3. animateMotion元素
路劲动画元素。这个元素大多数属性都和上面一样,只有下面几个稍微有点区别:
calcMode = "discrete | linear | paced | spline"
这个属性的默认值不同,在该元素中默认的是paced。
path = "<path-data>"
动画元素移动的路径,格式与path元素的d属性的值的格式是一致的。
keyPoints = "<list-of-numbers>"
这个属性的值是一系列分号给开的浮点数值,每个值的取值范围是0~1。这些值代表了keyTimes属性指定的对应时间点移动的距离,这里距离具体是多少是由浏览器自己决定的。
rotate = <number> | auto | auto-reverse"
这个属性指定了元素移动时旋转的角度。默认值是0,数字代表旋转的角度,auto表示随着路劲的方向转动物体。auto-reverse表示转向与移动方向相反的方向。
此外animateMotion元素的from,by,to,values的值都是坐标对组成的;x值与y值之间用逗号或空格分开,每个坐标对之间用分号隔开比如from="33,15"表示起点x坐标为33,y坐标为15。
指定运动路径的方式有两种:一种为直接给path属性赋值,一种为使用mpath元素作为animateMotionde的子元素指定路径。如果同时使用这两种方式,则使用mpath元素优先级高。这两种方式优先级都比values,from,by,to高。
看一个小例子:
<?xml version="1.0" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg width="5cm" height="3cm" viewBox="0 0 500 300" xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" > <rect x="1" y="1" width="498" height="298" fill="none" stroke="blue" stroke-width="2" /> <path id="path1" d="M100,250 C 100,50 400,50 400,250" fill="none" stroke="blue" stroke-width="7.06" /> <circle cx="100" cy="250" r="17.64" fill="blue" /> <circle cx="250" cy="100" r="17.64" fill="blue" /> <circle cx="400" cy="250" r="17.64" fill="blue" /> <path d="M-25,-12.5 L25,-12.5 L 0,-87.5 z" fill="yellow" stroke="red" stroke-width="7.06" > <animateMotion dur="6s" repeatCount="indefinite" rotate="auto" > <mpath xlink:href="#path1"/> </animateMotion> </path> </svg>
4. animateColor元素
颜色动画元素。这是一个过时的元素,基本上所有功能都可以用animate代替,所以还是不要用了。
5. animateTransform元素
变换动画元素。看看特殊的一些属性:
type = "translate | scale | rotate | skewX | skewY"
这个属性指定了变换的类型,translate是默认值。
from,by和to的值相应的都是对应变换的参数,这个还是与前面讲的变换是一致的。values则是一组分号隔开的这样的值系列。
支持动画效果的元素和属性
基本上所有图形元素(path,rect,ellipse,text,image...),容器元素(svg, g, defs, use, switch, clipPath, mask...)都支持动画。基本上大多数的属性都支持动画效果。详细的说明请参看官方文档。
五、理解SVG的viewport,viewBox,preserveAspectRatio
viewport
表示SVG可见区域的大小,或者可以想象成舞台大小,画布大小。
<svg width="500" height="300"></svg>
上面的SVG代码定义了一个视区,宽500单位,高300单位。
注意:
上面的SVG代码定义了一个视区,宽500单位,高300单位。
不带单位的情况 :不带单位的值被认为带的是"用户单位",就是当前用户坐标系的单位值。
带单位的情况
svg中相关单位与CSS中是一样的:em,ex,px,pt,pc,cm,mm和in。长度还可以使用"%"。
相对度量单位:em和ex也与CSS中一样,是相对于当前字体的font-size和x-height来说的。
绝对度量单位:一个px是等于一个"用户单位"的,也就是"5px"与"5"是一样的。但是一个px是不是对应一个像素,那就看有没有进行过一些变换了。
其他的几个单位基本都是px的倍数:1pt=1.25px,1pc=15px,1mm=3.543307px,1cm=35.43307px,1in=90px。
如果最外层的SVG元素的width和height没有指定单位(也就是"用户单位"),则这些值会被认为单位是px。
viewBox视窗变换
viewBox属性值的格式为(x0,y0,u_width,u_height),每个值之间用逗号或者空格隔开(已经绘制图形的坐标一样),它们共同确定了视窗显示的区域:视窗左上角坐标设为(x0,y0)、视窗的宽设为u_width,高为u_height;这个变换对整个视窗都起作用。
这里一定不要混淆:视窗的大小和位置已经由创建视窗的元素和外围的元素共同确定了(例如最外层的svg元素建立的视窗由CSS,width和height确定),这里的viewBox其实是设置这个确定的区域能显示视窗坐标系的哪个部分。
viewBox的设置其实是包含了视窗空间的缩放和平移两种变换。
变换的计算也很简单:以最外层的svg元素的视窗为例,假设svg的宽与长设置为width,height,viewBox的设置为(x0,y0,u_width,u_height)。则绘制的图形,宽和高的缩放比例分别为:width/u_width, height/u_height。视窗的左上角的坐标设置为了(x0,y0)。
在日常工作中,我们经常需要完成的一个任务就是缩放一组图形,让它适应它的父容器。我们可以通过设置viewBox属性达到这个目的。
能建立新视窗的元素
任何时候,我们都可以嵌套视窗。创建新的视窗的时候,也会创建新的视窗坐标系和用户坐标系,当然也包括裁减路径也会创建新的。下列是能建立新视窗的元素列表:
svg:svg支持嵌套。
symbol:当被use元素实例化的时候创建新的视窗。
image:引用svg元素时会创建新视窗。
foreignObject:创建新视窗去渲染里面的对象。
preserveAspectRatio-保持缩放的比例 属性
有些时候,特别是当使用viewBox的时候,我们期望图形占据整个视窗,而不是两个方向上按相同的比例缩放。而有些时候,我们却是希望图形两个方向是按照固定的比例缩放的。使用属性preserveAspectRatio就可以达到控制这个的目的。
这个属性是所有能建立一个新视窗的元素,再加上image,marker,pattern,view元素都有的。而且preserveAspectRatio属性只有在该元素设置了viewBox以后才会起作用。如果没有设置viewBox,则preserveAspectRatio属性会被忽略。
属性的语法如下:preserveAspectRatio="[defer] <align> [<meetOrSlice>]"
注意3个参数之间需要使用空格隔开。
defer:可选参数,只对image元素有效,如果image元素中preserveAspectRatio属性的值以"defer"开头,则意味着image元素使用引用图片的缩放比例,如果被引用的图片没有缩放比例,则忽略"defer"。所有其他的元素都忽略这个字符串。
align:该参数决定了统一缩放的对齐方式,可以取下列值:
none - 不强制统一缩放,这样图形能完整填充整个viewport。
xMinYMin - 强制统一缩放,并且把viewBox中设置的<min-x>和<min-y>对齐到viewport的最小X值和Y值处。
xMidYMin - 强制统一缩放,并且把vivewBox中X方向上的中点对齐到viewport的X方向中点处,简言之就是X方向中点对齐,Y方向与上面相同。
xMaxYMin - 强制统一缩放,并且把viewBox中设置的<min-x> + <width>对齐到viewport的X值最大处。
类似的还有其他类型的值:xMinYMid,xMidYMid,xMaxYMid,xMinYMax,xMidYMax,xMaxYMax。这些组合的含义与上面的几种情况类似。
meetOrSlice:可选参数,可以去下列值:
meet - 默认值,统一缩放图形,让图形全部显示在viewport中。
slice - 统一缩放图形,让图形充满viewport,超出的部分被剪裁掉。
六、SVG图形在移动端的自适应方法
在上面我们了解了viewBox视窗变换之后,其实可以得出一个公式:
width为svg的里面设置的宽度
height为svg里面设置的高度
uwidth为svg里面设置的宽度
uheight为svg里面设置的高度
cw为图形设置的高度
ch为图形设置的宽度
sW为实际宽度
sH为实际高度
实际宽度:sW = (width/uwidth)*cw
实际高度:sH = (height/uheight)*ch
例子:
<svg width="200" height="200" viewBox="0 0 100 100"> <rect x="0" y="0" width="200" height="200" fill="Red" /> </svg>
根据公式:
sW = (200/100)*200 = 400px
sH = (200/100)*200 = 400px
场景需求:通常来说我们的我移动端大部分视觉稿来说是640*960的(以这个为主呢,不说1080、720了),这里黑色不规则区域高度为200px,宽度为640px(640下面)
根据上面的公司,其实我们的svg里面的图形元素可以按实际640的大小写,viewbox的大小值也可以按,640的大小写,我们只需要控制svg容器上面的width、height大小的值变化,就可以达到适应的效果,看看代码:
<svg class="svg_pro" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0,0,640,200"> <polygon points="0,0 253,0 200,200 0,200" style="fill:rgba(0,0,0,.8);"></polygon> <polygon points="256,0 640,0 640,200 203,200" style="fill:rgba(0,0,0,.8);"></polygon> </svg>
svg基本上所有的属性(对于所有元素,不仅是文本)都可以用CSS与一个元素关联,并且所有CSS属性都在SVG图像中可用,那么我们在样式里面加上如下样式,就可以达到只适应:
svg.svg_pro { position: absolute; width: 100%; //这里宽度的值随着屏幕变化 height: 100%; //高度值随着屏幕变化(图片缩放,改变容器高度) top: 0; }
然并卵,这样就可以达到效果了,待续………………
参考资料:
突袭HTML5之SVG 2D入门(svg教程写的很全,推荐指数5星)
SVG 教程(w3school的svg教程,也不错)
mozilla svg教程(推荐给喜欢看英文教程的朋友)
知乎上面对svg的一些讨论(大家在使用时,有必要可以看一下)
推荐svg库: