浅淡SVG

898 阅读8分钟

一、SVG简述

1. 什么是SVG

SVG 是一种基于 XML 语法的图像格式,全称是可缩放矢量图(Scalable Vector Graphics)。其他图像格式都是基于像素处理的,SVG 则是属于对图像的形状描述,所以它本质上是文本文件,体积较小,且不管放大多少倍都不会失真。

2. 语法

SVG 代码都放在 svg 标签里。例如

<?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 xmlns="http://www.w3.org/2000/svg" version="1.1">
  <circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="gray" />
</svg>

SVGcircle 用来创建一个圆。cxcy 属性定义圆中心的 xy 坐标。如果忽略这两个属性,那么圆点会被设置为 (0, 0)r属性定义圆的半径。stroke为描边颜色,stroke-width为描边宽度,fill为填充颜色。 预览如图所示:

注:SVG的默认大小为300x150,(CSS规定了videoiframecanvas等替换元素的默认尺寸都是300x150)

3. SVG形状

  • 矩形 rect
  • 圆形 circle
  • 椭圆 ellipse
  • 线 line
  • 折线 polyline
  • 多边形 polygon
  • 路径 path

4. SVG元素

4.1 <text>

text标签用于绘制文本。

<svg>
  <text x="50" y="25">Hello World</text>
</svg>

显示如下: text的x属性和y属性,表示文本区块基线(baseline)起点的横坐标和纵坐标。文字的样式可以用classstyle属性指定。

4.2 <use>

use标签用于复制一个形状。

<svg>
  <circle id="myCircle" cx="5" cy="5" r="4"/>

  <use href="#myCircle" x="10" y="0" fill="blue" />
  <use href="#myCircle" x="20" y="0" fill="white" stroke="blue" />
</svg>

use的href属性指定所要复制的节点,x属性和y属性是左上角的坐标。另外,还可以指定width和height坐标。上述代码运行如图所示:

4.3 <g>

g标签用于将多个形状组成一个组(group),方便复用。

<svg>
  <g id="group">
    <rect x="10" y="20" height="50" width="75"/>
      <circle cx="100" cy="50" r="10"/>
    <text x="10" y="90">hello world</text>
  </g>

  <use href="#group" x="150" y="0" fill="gray"  />
</svg>

4.4 <defs>元素

defs元素用于自定义形状,它内部的代码不会显示,仅供引用。

 <svg>
   <defs>
     <g id="defs">
       <circle cx="50" cy="50" r="40" fill="none" stroke-width="2" />
       <circle cx="50" cy="50" r="10" />
     </g>
   </defs>
   <use href="#defs" x="0" y="0" fill="orange"  stroke="orange" />
 </svg>

运行结果如下:

4.5 <pattern>

<pattern> 标签用于自定义一个形状,该形状可以被引用来平铺一个区域。

<svg>
   <defs>
     <pattern id="dots" x="0" y="0" width="30" height="30"  patternUnits="userSpaceOnUse">
       <circle fill="black" cx="10" cy="10" r="10" />
     </pattern>
   </defs>
   <rect x="0" y="0" width="100%" height="100%" fill="url(#dots)" />
 </svg>

5. SVG viewPort、viewBox

5.1 定义

viewPort 指的是SVG的视窗大小

viewBox 允许指定一个给定的一组图形伸展以适应特定的容器元素。

viewBox 属性的值是一个包含4个参数的列表 min-x, min-y, width and height, 以空格或者逗号分隔开, 在用户空间中指定一个矩形区域映射到给定的元素。

5.2 作用

以下面代码为例:

<svg width="300" height="300" viewBox="0 0 200 200" class="svg">     
   <rect width="50" height="50" fill="#000">
</svg>

显示如下图所示:

  • SVG的viewport的大小就是300*300的矩形区域,用灰色填充。
  • viewBox的大小就是200*200的矩形区域,位置坐标为(0, 0)。这时候矩形(黑色色块)显示的大小为75*75300/200*50)。

但是实际很多 SVG 的 viewBox 的宽高比和 viewport 的宽高比是不同的。那么在不同的情况下 viewBox 和 viewport怎么处理?viewBox 的4个参数到底有什么作用?viewBox 比 viewport区域大可以吗?SVG是怎么处理的呢?这就要和preserveAspectRatio属性值相关了。

preserveAspetRation 属性是和 viewBox 属性配合使用的,指出了如何缩放及如何对齐viewBox到viewport上。

如果没有指定viewBox属性,那么该属性是会被忽略的。它有两个参数,默认值为xMidYMid meet 第一个参数有9个值:

  • xMinYMin
  • xMinYMid
  • xMinYMax
  • xMidYMin
  • xMidYMid(默认)
  • xMidYMax
  • xMaxYMin
  • xMaxYMid
  • xMaxYMax xy 表示对齐的轴线,minmidmax 示对齐的方式。min 往坐标小的方向对齐;mid 中对齐;max 往坐标大的方向对齐。

第二个参数有两个值可选:meetslice

  • meet 是将 viewBox 调整到可以在 svg 画布中完全展示。类似 css 里 background-size: contain(默认)
  • slice 是自动调整 viewBox 到撑满整个svg画布。类似 background-size: cover

preserveAspectRatio 还有个单独使用的参数:none。 来看一段代码:

<svg width="300" height="150" viewBox="0 0 200 200" class="svg" preserveAspectRatio="none">     
  <rect width="50" height="50" fill="#000">
</svg>

这段代码和上面不同的是,SVG的 viewPort 高度修改为 150,并且 preserveAspetRation 设置为 none。 这段代码运行结果如图所示:

xMinYMin 强制等比例缩放,原始的正方形变成了长方形。

小tips: PS绘制的 SVG 与 AI 绘制的区别:

juejin.cn/post/687588…

二、SVG动画

1. SVG描边动画

主要是利用SVG的 stroke-dasharraystroke-dashoffset 来实现。

stroke-dasharray: 用于创建虚线,可以为多个值。 stroke-dasharray="10" 显示为:实线为 10,间隔为 10 的排布重复下去。 stroke-dasharray="10, 5" 显示为: 实线为 10,间隔为 5 的排布重复下去。

stroke-dashoffset:属性指定了dash模式到路径开始的距离,需要设置stroke-dasharray才生效。

例如:

jianxiujiucan.github.io/svg/stroke1…

tips: js的getTotalLength()方法可以获取到path的长度,以像素为单位,返回路径的长度(仅适用于path元素)。。

我们还可以利用这两个属性分别来实现SVG圆环进度条的动画。 例如: codepen.io/jianxiujiuc…

这两个动画实现的效果是一致的,但是实现的方法却不一样。一个是利用了dashoffset的距离偏移,另一个则是利用dasharray虚线的间距来实现。

我们可以通过这两个属性的特性来制作一些比较有趣的loading动画:

jianxiujiucan.github.io/svg/loading…

2. SVG路径动画

主要利用两个属性:offset-pathoffset-distance

offset-path:指定元素要遵循的运动路径,路径一般为SVG的path值。

offset-distance:表示运动的距离

利用路径offset-path让元素沿着不规则路径运动,结合offset-distance就可以让元素动起来。


例如:

.round{
    offset-path: path("M30.74,132.25c0,0,49-84,149-62s170,194,275,169s60-154,174-156s209,184,209,184");
}
@keyframes move {
    0% {
        offset-distance: 0%;
    }
    100% {
        offset-distance: 100%;
    }
}

jianxiujiucan.github.io/svg/offset-…

注意,路径也是有方向的,路径与绘制的起始结束的方向保持一致。如此路径是一个闭合路径,那么我们可以在PS或AI里修改路径的起始点来修改路径的方向。

具体操作可以看这篇文章: juejin.cn/post/688413…

元素沿路径运动的方向可以通过offset-rotate(之前属性为offset-rotation,已废弃)来设置,单位是deg

需求应用: jianxiujiucan.github.io/svg/speed/i…

3. SVG变形动画

3.1 SVG 相同点数变形动画

 <svg style="width: 200px; height:200px" viewBox="0 0 200 200">
     <path fill="#1EB287">
         <animate attributeName="d" 
            dur="2000ms" 
            repeatCount="indefinite" 
            calcMode="linear"
            keyTimes="0 ; 0.6 ;  1"
            values="
            M9.1,88.4c0,41.7,31.5,47.8,52.7,61.8c20.5,13.5,35.1,32,37.4,39.8c2-7.7,18.2-26.7,37.2-40.2c20.8-14.8,52.9-26.9,52.7-61.8c-0.4-63.6-57.8-64.8-90-21.1C66.7,23.7,9.1,25.6,9.1,88.4z;
M98.74,184.27c79.81-20.51,90-84.06,90-105.03c0-20.97-6.83-43.06-24.83-65.98c-13.55,5.04-43.15,7.27-65.17,0
    c-22.02,7.27-51.62,5.04-65.17,0C15.57,36.18,8.74,58.27,8.74,79.24C8.74,100.21,18.94,163.76,98.74,184.27z;
M90.6,149.3c22.9,0,65.5-0.6,91.7-0.9c-15.9-25.6-24.1-37.9-49.2-75.1C115.3,47.1,98.4,21.3,88.2,9
	c-8,11.9-25.4,41.3-42,69.7c-20.6,35.3-29,47.6-39.3,69.7C28.2,149.1,69.6,149.3,90.6,149.3z" />
      </path>
  </svg>

预览: jianxiujiucan.github.io/svg/path-an…

下面来解析一下上面的代码。

  • keyTimes: 和 CSS 中定义的 @keyframes 一样。通过 0-1 之间的值,定义每段动画完成的时间。keyTimes 需要和 values 里面定义的帧数一致。
  • calcMode: 用来定义动画具体的插值模型。取值有: discrete | linear[default] | paced | spline。具体可以参考 MDN。这里我们主要介绍一下 spline。该值表示每个动画间使用自定的贝塞尔变换曲线。一般来说,使用 linear 已经足够了,这样就不用麻烦去定义下面的 keySplines 属性。但是如果定义了spline,就必须要给keySplines赋值了。
  • keySplines:该值用来具体定义动画执行时的 贝塞尔曲线。使用格式是通过 ; 来分隔每一个值。即,cubic-bezier(.31,.57,.93,.46) 为一组。使用 keySplines 表达,则为:keySplines = ".31,.57,.93,.46;"。当然,里面的贝塞尔曲线组数为 整个动画帧数 - 1
  • value :value值里存放要变形的SVG path路径,注意一定是path格式。并且每个要变形的形状的路径的点数需要保持一致,否则没有过渡效果。如果点数不一致,可以在AI等可以绘制SVG的软件里,通过增减锚点来达到一致。

3.2 SVG任意点数变形动画

当我们的路径动画锚点特别多,就不适合用上面的方式来进行变形了,毕竟增删锚点也是个很累人的活。 这时候可以依靠插件来实现任意点数的变形动画。

主要使用两个插件:TweenMax.min.jsMorphSVGPlugin.min.js

插件的官方网站: www.tweenmax.com.cn/start/morph…

效果如图:

DEMO: jianxiujiucan.github.io/demo/svg.ht…

三、SVG制作字体

1. Unicode

首先来了解一下Unicode。Unicode(统一码、万国码、单一码)是计算机科学领域里的一项业界标准,包括字符集、编码方案等。Unicode 是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。

简言而之,每一个字符(中文or英文)都有对应的一个Unicode。

中文范围 4E00(对应的中文为)~ 9FA5(对应的中文为)。

可以通过线上的网站来查到汉字对应的Unicode值。 www.atool.org/chinese2uni…

2. 字体上传

我们可以通过阿里的图标库来上传字体文件 www.iconfont.cn

3. iconfont

Iconfont 就是指用字体文件取代图片文件,来展示图标、特殊字体等元素的一种方法。使用iconfont制作图标已经成为主流。

同样通过阿里的图标库来创建iconfont文件。但是除了官网上的注意点之外,还有几点是一定要注意的:

图形一定要对齐像素格,将线对齐在像素格中。如未对齐像素格,单精屏显示器线框会发虚。

在限定边框内绘制完成图形,并且高度不要使用奇数,否则图标会发虚。

参考文章: