25

记一次前端SVG实战知识分享会

记录了我在组内的技术分享, 有同样需求的同学可以参考一下
分享全程下来时间大约 40分钟

image

一. svg与前端工程师

1. 作为一名前端工程师不可能不与svg打交道, 如今掌握svg的基本知识是咱们的基本技能.
2. 学svg之前最好先学一学xml的基本知识, 这样可以更好的理解文件结构.
3. svg是很不错, 但是并不是任何地方都要使用, 学习不要太刻板.

本篇重点是基础知识, 希望您看完之后可以对svg做出一些简单的修改, 或者是一个小图片不用再等ui做完给我们, 我们可以自己动手制作.

二. xml简介 (不会说的太详细)

XML 被设计用来传输和存储数据, 指可扩展标记语言(_EX_tensible _M_arkup _L_anguage)
HTML 被设计用来显示数据。

这个头部标签 <?xml version="1.0" standalone="no"?>
  1. XML标准文件头
  2. 版本号是1.0
  3. standalone代表这个xml文件是独立的还是依赖与外部dtd文件的 (作用是定义 XML 文档的合法构建模块) 类似java中的接口.
现在很多配置文件还是用xml的形式比如java代码, 这些配置文件应该是用json更好.

三. svg简介

SVG 是使用 XML 来描述二维图形和绘图程序的语言。(节选自w3school)

  • SVG 指可伸缩矢量图形 (Scalable Vector Graphics)
  • SVG 用来定义用于网络的基于矢量的图形
  • SVG 使用 XML 格式定义图形
  • SVG 图像在放大或改变尺寸的情况下其图形质量不会有所损失
  • SVG 是万维网联盟的标准
  • SVG 与诸如 DOM 和 XSL 之类的 W3C 标准是一个整体
  1. 什么是矢量, 矢量图形: 面向对象的图像或绘图图像,在数学上定义为一系列由线连接的点, 一个一个的图形对象, 任意的组合.

矢量图介绍短片

  1. 不失真属于老生常谈的问题了, 其实在我看来svg图片可以被我们随便修改他的样式才是最重要的, 毕竟一个png文件不好通过代码修改他的背景色, 或是某一块的大小比例.
  2. 缺点: 在window系统里, 没有图例显示不方便查看, 在mac电脑里就有个缩略图, 没找照一张图片还要把svg全打开挨个找...

<svg width="500" height="500" version="1.1"
xmlns="http://www.w3.org/2000/svg">

  1. 定义了svg的宽高
  2. 定义了使用1.1版本svg, 就像html一样有 4与5, svg的版本也在变化.
  3. xmlns是xml namespace的缩写,也就是XML命名空间,xmlns属性可以在文档中定义一个或多个可供选择的命名空间。该属性可以放置在文档内任何元素的开始标签中。该属性的值类似于URL,它定义了一个命名空间,浏览器会将此命名空间用于该属性所在元素内的所有内容。

例如SVG< a>元素和HTML< a>如果一个被称为svg:a和另一个html:a,则可以区分该元素, 作用就是防止svg标签内的元素与html元素混乱一团.
html5中不写这句影响也不大.

兼容性如下

image

四. 基本图形

  • svg有很多基本图形如: 矩形、圆形、直线、多点成线、多边形.
  • 这些图形我们可以直接使用
<?xml version="1.0" standalone="no"?>
<!-- 1: 整体的长宽, 规则定义  -->
<svg width="500" height="500" version="1.1"
xmlns="http://www.w3.org/2000/svg">
<!-- 1:矩形 -->
<!-- x, y 左上角的位置 -->
<!-- fill: 填充的颜色 -->
<rect  width="100" height="100" style="x:20; y:20;" />

<!-- 1:圆形 -->
<!-- 2: cx,cy 圆心的坐标 -->
<!-- 3: r半径 -->
<circle cx="70" cy="220" r="50" fill="red"></circle>


<!-- 3: 直线 -->
<!-- 两个点的坐标 -->
<line x1="160" y1="80" x2="300" y2="80" style="stroke:green;stroke-width:16;"></line>

<!-- 4: 多点线 -->
<!-- 会自动把第一个点与最后一个点连接起来 -->
<!-- points:一组一组的xy坐标 -->
<polyline points="500,60 330,60 420,180"></polyline>

<!-- 5: 多边形 -->
<polygon points="470,400 450,320 410,320 410,340 410,440" style="fill:red;stroke:red;stroke-width:2"></polygon>
</svg>

如图所示:

image

  1. 这里的宽高与xy的距离你可以按px理解, 但其实这个是他的比例, 使用的时候会按这个比例等比缩放.
  2. style="stroke:green;stroke-width:16;" 定义: 如果在线内定义的是 线条的颜色为绿色, 线的宽度为16
  3. style="fill:red;stroke:red;" fill指的是填充颜色, stroke边的颜色(有时候我面试的同学说经常使用svg, 但是fill属性都不知道, 场面很尴尬.)
  4. style并不是绝对的, 比如第一个矩形我也可以写成<rect width="100" height="100" x="20" y="20" />
  5. 一起其他属性: transform="rotate(30)" 旋转角度,这里不用写deg, rx:20;ry:60; 角的弧度可以做矩形的圆角.
  6. 知道了svg无非也就是个dom那我们就可以通过获取元素的形式进行对svg内部图像的修改了, 比如获取到这个svg里面的矩形setAttribute('x', 200)让他x轴变为200

五. 视野与视框

<?xml version="1.0" standalone="no"?>

<!-- 1: 视野 -->
<!-- viewBox: 我能看到哪一部分, 当前就是左上角 -->
<!-- viewBox就算小了, 但是整体的宽高是不变的, 所以会有放大缩小效果 -->
<!-- 2: 如果viewport和viewBox的宽高比不相同。你需要自己来指定如何在SVG阅读器(如浏览器)中显示SVG图像。你可以在<svg>中使用preserveAspectRatio属性来指定。 -->
<!-- preserveAspectRatio   meet就是保持原比例不失真-->
<svg width="500" height="500" version="1.1"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 100" preserveAspectRatio="none meet">
<rect 
  width="200" height="200"
  style="x:20; y:20; rx:20;ry:60; fill:rgb(0,0,255);stroke-width:16;
stroke:black"/>

</svg>

1: 不设置viewBox
image

2: 设置后
image

viewBox不影响整体svg的大小与比例, 只是以多大的窗口展示这个svg图片

六. 样式分组(事情变得有趣了)

任何形式的代码都存在如何复用的问题, 我们不可能在画出一个不规则图形然后想再画一个一模一样的图形时, 重新画一遍
下面是复用"样式", 在g标签里面写上样式, 内部的标签会默认使用.

神奇的 g 标签

<?xml version="1.0" standalone="no"?>
<!-- 1: <g>标签分组了, 就有面向对象的概念了 -->
<svg width="500" height="500" version="1.1"
xmlns="http://www.w3.org/2000/svg">
<!-- 定义了整体的属性 -->
<!-- 2: 可以多层嵌套替换 -->
<g style="fill:rgb(0,0,255);stroke-width:16">
  <rect 
    width="100" height="100"
    style="x:20; y:20; rx:20;ry:60;
  stroke:black"/>

  <rect 
    width="100" height="100"
    style="x:20; y:140; rx:20;ry:60;
  stroke:black"/>
</g>
</svg>

效果如下图, 一模一样的两个图形
image

当然<g>标签也可以嵌套使用
<?xml version="1.0" standalone="no"?>
<svg width="500" height="500" version="1.1"
xmlns="http://www.w3.org/2000/svg">
<g style="fill:rgb(0,0,255);stroke-width:16">
  <rect 
    width="100" height="100"
    style="x:20; y:20; rx:20;ry:60;
  stroke:black"/>

  <rect 
    width="100" height="100"
    style="x:20; y:140; rx:20;ry:60;
  stroke:black"/>
  
  <g style="fill:red;stroke-width:16">
    <rect 
      width="100" height="100"
      style="x:20; y:260; rx:20;ry:60;
    stroke:black"/>
  </g>
</g>
</svg>

如图:
image

七. 复用

我画好的图形, 我当然可以复制一份继续使用啦

使用<use>标签进行引用图形, 并且在use标签上进行新图形的操作, 可以直接设置xy之类的东西.

<?xml version="1.0" standalone="no"?>
<svg width="500" height="500" version="1.1"
xmlns="http://www.w3.org/2000/svg">
  <g id="cc">
    <rect width="100" height="100" x="20" y="20" />
  </g>
 <use xlink:href="#cc" transform="translate(160,0)" fill="red"/>
</svg>

这里可能会出现作用域的问题, 但是放在html里面就没问题了
后面会讲问什么放在html里面会好, 已经如何解决这个问题!!!
有问题的同学可以用下面的代码

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
<svg width="500" height="500" version="1.1"
xmlns="http://www.w3.org/2000/svg">
  <g id="cc">
    <rect width="100" height="100" x="20" y="20" />
  </g>
 <use xlink:href="#cc" transform="translate(160,0)" fill="red"/>
</svg>
</body>
</html>

效果如下:
image
image

玩到这里是不是有些.svg里面的代码在干什么已经能看懂小半了!!! 这就是会的越多越开心.

八. 渐变

<?xml version="1.0" standalone="no"?>

<svg width="500" height="500" version="1.1"
xmlns="http://www.w3.org/2000/svg">

  <!-- 1: 定义了一组渐变, 设置id方便引用 -->
  <defs>
      <!-- 这里指定了渐变的区域, 1-0的范围 -->
      <linearGradient id="orange_red" x1="0%" y1="0%" x2="100%" y2="0%">
      <stop offset="0%" style="stop-color:rgb(255,255,0);
      stop-opacity:1"/>
      <stop offset="100%" style="stop-color:rgb(255,0,0);
      stop-opacity:1"/>
      </linearGradient>
  </defs>
  <!-- 1: 引入相应的渐变颜色 -->
  <ellipse cx="200" cy="190" rx="85" ry="55"
  style="fill:url(#orange_red)"/>

</svg>
  1. <defs>里面定义了一组渐变规则, 因为xml只能所有都用标签标示, 你可以理解为这个定义了个类.
  2. <defs>标签里面定义的内容是不展示的
  3. <linearGradient> 线性渐变标签, <radialGradient>放射性渐变标签(这个原理都一样)
  4. <stop> 规定了n%的位置的颜色
  5. <ellipse> 是用来做椭圆的

如图所示:
image

九. 填充

<?xml version="1.0" standalone="no"?>

<svg width="500" height="500" version="1.1"
xmlns="http://www.w3.org/2000/svg">
<!-- 1: 定义填充类 -->
<defs>
<!-- 2: 内容写在这里 -->
<pattern id="cc" x="0" y="0" width="0.2" height="0.2">
   <circle cx="10" cy="10" r="10" fill="red">
   </circle>
</pattern>
</defs>
  <rect 
    width="400" height="400"
    fill="url(#cc)"
    style="x:20; y:20; rx:60;ry:60;stroke:black"/>
</svg>
  1. <pattern> 填充功能的标签
  2. 这里你可以理解为div的背景图案, 但是没有设置 background-repeat: no-repeat;

如图所示:
image

十. path的用法(可以一口气画的好长好长...)

<?xml version="1.0" standalone="no"?>

<svg width="600" height="600" version="1.1"
xmlns="http://www.w3.org/2000/svg">
<!-- 1: 把path当成一支画笔, path就是一气呵成的绘制操作 -->
<!-- 2: M 是移动的xy  m是移动的相对距离 c是curveto曲线图 -->
<!-- 3: L画直线 -->
<path d="M153 334
C153 334 151 334 151 334
C151 339 153 344 156 344
C164 344 171 339 171 334
C171 322 164 314 156 314
C142 314 131 322 131 334
C131 350 142 364 156 364
C175 364 191 350 191 334
C191 311 175 294 156 294
C131 294 111 311 111 334
C111 361 131 384 156 384
C186 384 211 361 211 334
C211 300 186 274 156 274"
style="fill:white;stroke:red;stroke-width:2"/>

</svg>
  1. <path>标签类似一气呵成的画笔, 里面会有超多绘制操作, 有了这个标签就可以很方便的封装绘制svg的编辑器了.
  2. M153 334 的意思就会在坐标为153 334的点上绘制
  • M = moveto
  • L = lineto
  • H = horizontal lineto
  • V = vertical lineto
  • C = curveto
  • S = smooth curveto
  • Q = quadratic Bézier curve
  • T = smooth quadratic Bézier curveto
  • A = elliptical Arc
  • Z = closepath

如图所示:
image

简单的也有

<?xml version="1.0" standalone="no"?>
  <svg width="600" height="600" version="1.1"
xmlns="http://www.w3.org/2000/svg">
  <path d="M150 0 L75 200 L225 200 Z" />
</svg>
  1. M150 0 绘制起始点坐标
  2. L75 200 连线到75 200
  3. L225 200 连线到255 200
  4. Z 结束绘制, 提笔.

如图所示:
image

十一. 文本输入

怎么可能少了文字的输入
<?xml version="1.0" standalone="no"?>
<svg width="500" height="500" version="1.1"
xmlns="http://www.w3.org/2000/svg">
<!-- 1: 理论上svg并不是一个专业处理文字的载体 -->
<!-- 2: style标签可以使用大部分css属性啦, 不用要px -->
<!-- 3: xy对应的是左下角的基线, 而不是完美的左下角 -->
<!-- 4: 文字的颜色也要放在fill属性里面, 这也更符合工程化 -->
<text x="200" y="200" style="font-size:26;" fill="red">蚊子蚊子1</text>
<!-- 5: 针对里面每一个字符设置距离 -->
<!-- dx dy 具体到每个文字的距离 -->
<!-- 那么我其实可以巧用svg来搞点花里胡哨的 -->
<!-- 用波浪形画个❤ -->
<!-- 再加上动画效果, 就是扭动起来的文字啦 -->
<text x="200" y="300" dx="0 20 60 " dy="0 20 40" style="font-size:26;" fill="blue">蚊子蚊子2</text>

<!-- tspan标签对文字的单独处理(含镂空!!!!) -->
<text x="200" y="100" style="font-size:40">
  <tspan fill="red">蚊子3</tspan>
  <tspan stroke="blue" fill="none">蚊子4</tspan>
  </text>
</svg>
  1. <text>标签用来表示文字
  2. dx定义每个文字之间的间距
  3. <tspan> 就是<text>里面单独处理字符的标签
  4. fill="none" 就可以产生扣动字了

如图所示:
image

十二. 路径文本(让你的文字沿着路径排列而已)

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
<title>textpath</title>
</head>
<body>
<svg xmlns='http://www.w3.org/2000/svg' width='800' height='600'>
    <path id="path1" d='M 100 200 Q 200 100 300 200 T 500 200' stroke='rgb(0,255,0)' fill='none'>
    </path>
    <text style='font-size:24px;'>
        <textpath xlink:href='#path1'>
            学来学去学来, 你还学得动吗哈哈哈!!
        </textpath>
    </text>
</svg>
</body>
</html>
  1. 上面使用的path标签赋予颜色是为了让大家看清文字走向
  2. <textpath>标签需要引用一个走向(从此以后你可以画出各种线路的文字, 是不是可以秀给女朋友看??)
  3. fill='none'很重要, 不然他会变成面积图

    去掉 fill='none':
    image

    加上 fill='none:
    image

    加上这个就可以不用在html文件中才能显示了, 也就是规定了作用域

<?xml version="1.0" standalone="no"?>
<svg width="500" height="500" version="1.1"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> 
<defs>
  <path id="my" d="M 100 200 Q 200 100 300 200 T 500 200" />
</defs>
<text x="10" y="200" style="font-size:26" fill="red">
 <textPath xlink:href="#my">
 学来学去学来, 你还学得动吗哈哈哈!!
 </textPath>  
</text>
</svg>
  1. xmlns:xlink= 属性规范了作用域
  2. 这意味着文档可访问 XLink 的属性和特性,表示前缀为xlink的元素应该由理解该规范的UA使用xlink规范来解释, 你可以理解为不与html冲突了.

十三. svg的引入(直接写svg, <embed> <object> <iframe>标签引入, 其实img也可以的 )

使用svg可不只是把svg放在html结构中

  1. 直接写在html中, 这个我上面演示过,
  2. <embed> 标签是 HTML 5 中的新标签, 标签定义嵌入的内容,也就相当于把svg结构直接插进来了。
  3. <object> 标签是 HTML 4 的标准标签,被所有较新的浏览器支持。它的缺点是不允许使用脚本, 向 HTML 代码添加一个对象, 感觉可用于服务端渲染的项目快速取得数据。
  4. iframe都快被淘汰了就别用了, 这里也不说用法了.
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <!-- 1: 这个为啥网上没人说? -->
  ![](./2.基本图形.svg)
  <!-- 2: embed标签引入 -->
  <embed id="cc" src="./2.基本图形.svg" width="500" height="500"
  type="image/svg+xml"
  pluginspage="http://www.adobe.com/svg/viewer/install/" />
  <!-- 3: object -->
  <object data="./2.基本图形.svg" width="300" height="100" 
  type="image/svg+xml"
  codebase="http://www.adobe.com/svg/viewer/install/" />
</body>
</html>

十四. 做图工具

  1. SVG.js 官网
  2. Adobe Illustrator 官网
  3. 菜鸟工具

十五. 实际应用时如何破话svg的比例

还是要单独强调一下, svg有自己的比例, 但是如果你的项目需要把svg图片撑满容器的时候, 你就要在svg标签上设置preserveAspectRatio="none meet", 否则是不允许破话svg比例的.(也可直接preserveAspectRatio ="none")

end 结束

svg不是前端工程师的必修课, 同时也不是一门必须使用的技术, 不要听说svg好就强制使用,我们要知道它好在哪,怎么用更好才行.
但通过学习svg的相关知识可以使我们可以靠自己做出更多绚丽的东西, 也会扩充很多有趣的知识点, 铸造我们更好的思维与知识体系.
这次就是这样, 希望和你一起进步.


lulu_up
5.7k 声望6.9k 粉丝

自信自律, 终身学习, 创业者