一、理解html、xhtml、xml
html是超文本标记语言,xml是可拓展的标记语言,两者均是从SGML(标准通用标记语言)中抽取发展而来,html的语法比较松散、扩充性也不太好,所以出现了xhtml(可拓展的超文本标记语言),它本质上属于xml的方言,不过这玩意随着html5的流行就被淘汰掉了。
二、xmlns、xmlns:xlink和version
xmlns是xml命名空间,用来告诉浏览器接下来的标签属于xml的哪种方言。内联svg可以不写,但是外部使用时必须写。
<html xmlns="http://www.w3.org/1999/xhtml">
<body>
<!-- 在这里放置一些 XHTML 标签 -->
<svg xmlns="http://www.w3.org/2000/svg" width="300px" height="200px">
<!-- 在这里放置一些 SVG 标签 -->
</svg>
<!-- 在这里放置一些 XHTML 标签 -->
</body>
</html>
xmlns:xlink,声明了一个命名空间,该命名空间以xlink作为前缀。内联svg可以不写,但是外部使用时带有xlink:的必须写。
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<script xlink:href="cool-script.js" type="text/ecmascript"/>
</svg>
version用于指明svg文档遵循的规范,有1.0和1.1。该属性纯粹是一个说明,对渲染和处理无任何影响。
三、svg标签的宽高和viewBox之间的关系
注:与img标签一致,CSS宽高会覆盖掉svg标签上的宽高
计算关系如下:
<!-- 什么都不写,则 width:300, height:150, viewBox: 0 0 300 150 -->
<svg></svg>
<!-- 只写宽高,则 viewBox: 0 0 width height -->
<svg width="200" height="100"></svg>
<!-- 只写viewBox,则 width=父元素宽, height=父元素宽/200*100 -->
<svg viewBox="0 0 200 100"></svg>
<!-- 写宽高中的一个和viewBox,则这里的height=300/200*100=150 -->
<svg width="300" viewBox="0 0 200 100"></svg>
来个实际的例子:
<svg width="300" viewBox="0 0 200 100">
<!-- 下面的百分比都是根据viewBox来计算的,width=200*100%=200, height=100*80%=80 -->
<rect x="0" y="0" width="100%" height="80%"></rect>
<!-- cx=200*50%=100, cy=100*70%=70, r=10 -->
<circle cx="50%" cy="70%" r="10" fill="white"></circle>
</svg>
<!-- 若上面的r写成百分比形式如 10%,计算方式为:√(200^2+100^2) / √2 * 10% = 15.81 -->
⬆️ 算出来的是一个宽200、高80的矩形,和一个半径10的圆。
实际上画出来的是一个宽300、高120的矩形,和一个半径15的圆。这是因为当 SVG 的 viewbox 属性与视图属性宽高比一致时,会自动缩放。
(1)改变viewBox的前两个值看一下
<svg width="300" viewBox="-100 -20 200 100">
<!-- 下面的百分比都是根据viewBox来计算的,width=200*100%=200, height=100*80%=80 -->
<rect x="0" y="0" width="100%" height="80%"></rect>
<!-- cx=200*50%=100, cy=100*70%=70, r=10 -->
<circle cx="50%" cy="70%" r="10" fill="white"></circle>
</svg>
意思是(-100, -20)这个点作为左上角,画一个宽200、高100的矩形,再自动缩放到300x150的大小。如下图:
(2)设置一下height,让SVG 的 viewbox 属性与视图属性宽高比不一致,此时可以设置preserveAspectRatio该属性来控制图形应该怎么被缩放。
<svg width="300" height="200" viewBox="0 0 200 100" preserveAspectRatio="xMidYMid meet">
<!-- 下面的百分比都是根据viewBox来计算的,width=200*100%=200, height=100*80%=80 -->
<rect x="0" y="0" width="100%" height="80%"></rect>
<!-- cx=200*50%=100, cy=100*70%=70, r=10 -->
<circle cx="50%" cy="70%" r="10" fill="white"></circle>
</svg>
preserveAspectRatio的默认值为xMidYMid meet,xMidYMid意思是将 viewbox 和视图在x轴和y轴上的中线都对齐,meet可以理解为css里的background-size被设置为contain,slice则可以类比为cover。
四、path标签
path是用来定义形状的通用元素,基本上所有的形状都可以用path来绘制。SVG 定义了六种路径命令类型,一共 20条命令(大写为绝对坐标,小写为相对坐标):
| 类型 | 命令 | 注意点 |
|---|---|---|
| 移动到 | M,m | --- |
| 画线至 | L,l H,h V,v | --- |
| 三次贝塞尔曲线 | C,c S.s | s表示平滑的三次bezier曲线 |
| 二次贝塞尔曲线 | Q,q T,t | t表示平滑的二次bezier曲线 |
| 椭圆曲线 | A,a | 半径不满足其余条件时,会等比放大 |
| 封闭路径 | Z,z | 大小写无区别 |
<svg width="400" height="200" stroke="black" stroke-width="3" fill="none">
<path d="M 10,10 L 30,30 h 20 v 20 c 0,20 20,20 20,0 s 20,-20 20,0 q 20,20 0,40 t 0,40 a 40 20 0 1 1 -80,0 Z" />
</svg>
从(10, 10)开始画一条到(30, 30)的线,再水平画一条长20的线,再垂直画一条长20的线,再画两条三次bezier曲线,再画两条二次bezier曲线,再画一个椭圆曲线,最后闭合。如下:
可参考:svg中path标签的d属性 、 bezier曲线原理
五、一些额外标签
1、use标签、g标签、defs标签。其中use用于复制一个形状;g用于将几个形状合成一个组;defs包裹的标签不会直接显示,仅用于引用。
<svg width="400" height="200">
<defs>
<g id="audi" stroke="black" stroke-width="3" fill="none">
<circle cx="50" cy="50" r="15" />
<circle cx="70" cy="50" r="15" />
<circle cx="90" cy="50" r="15" />
<circle cx="110" cy="50" r="15" />
</g>
</defs>
<use xlink:href="#audi" />
</svg>
2、linearGradient标签、stop标签。其中linearGradient用于定义线性渐变,stop定义颜色坡度。
<svg width="400" height="200">
<defs>
<g id="audi" stroke-width="3" fill="none">
<circle cx="50" cy="50" r="15" />
<circle cx="70" cy="50" r="15" />
<circle cx="90" cy="50" r="15" />
<circle cx="110" cy="50" r="15" />
</g>
<linearGradient id="myGradient" gradientTransform="rotate(90)">
<stop offset="5%" stop-color="gold" />
<stop offset="95%" stop-color="red" />
</linearGradient>
</defs>
<use xlink:href="#audi" stroke="url(#myGradient)" />
</svg>
3、clipPath标签、pattern标签。其中clipPath用于裁剪,仅在clipPath的范围内显示;pattern用于填充。
<svg width="400" height="200">
<defs>
<clipPath id="myClip">
<circle cx="200" cy="50" r="35" />
</clipPath>
<pattern id="star" viewBox="0,0,10,10" width="10%" height="10%">
<polygon points="0,0 2,5 0,10 5,8 10,10 8,5 10,0 5,2" />
</pattern>
</defs>
<!-- 用star填充这个rect -->
<rect width="100" height="100" fill="url(#star)" />
<!-- 用star填充这个rect后,再用myClip裁剪 -->
<rect x="150" width="100" height="100" clip-path="url(#myClip)" fill="url(#star)" />
</svg>
4、animate标签、animateTransform标签。除了transform动画需要用animateTransform外,其余动画均可以用animate。
<svg width="400" height="200">
<image class="" href="./konglong.png">
<!-- 宽度从0到100 -->
<animate
attributeName="width"
from="0"
to="100"
dur="3"
repeatCount="indefinite"
></animate>
<!-- 旋转360度,基点从(0, 0)到(50, 50) -->
<animateTransform
attributeName="transform"
type="rotate"
from="0 0 0"
to="360 50 50"
dur="3"
repeatCount="indefinite"
/>
</image>
</svg>