# SVG 相关知识点

TIP

图形分为位图和矢量图。位图是基于颜色的描述,是由像素点组成的图像;而矢量图是基于数学矢量的描述,是由几何图元组成的图像,与分辨率无关。可缩放矢量图形,即 SVG,是 W3C XML 的分支语言之一,用于标记可缩放的矢量图形。

# SVG 基本形状和样式设置

# 矩形【rect】

rect元素会在屏幕上绘制一个矩形 。其实只要 6 个基本属性就可以控制它在屏幕上的位置和形状

属性 说明
x 矩形左上角的 x 位置
y 矩形左上角的 y 位置
width 矩形的宽度
height 矩形的高度
rx 圆角的 x 方位的半径
ry 圆角的 y 方位的半径

TIP

[注意]如果只设置 rxry 任意一个,则另一个将默认相等

如果没有设置圆角,则默认为 0

<!--可复制插入浏览器中节点展示 -->
<svg>
  <rect x="10" y="10" width="30" height="30" fill="#c00" />
  <rect x="60" y="10" rx="10" width="30" height="30" fill="42b983" />
</svg>

# 圆形【circle】

circle 元素会在屏幕上绘制一个圆形。它只有 3 个属性用来设置圆形

属性 说明
r 圆的半径
cx 圆心 x 的位置
cy 圆心 y 的位置
<svg>
  <circle cx="25" cy="25" r="20" fill="#c00" />
</svg>

# 椭圆【ellipse 】

椭圆 Ellipse 是 circle 元素更通用的形式,可以分别缩放圆的 x 半径和 y 半径(通常数学家称之为长轴半径和短轴半径)

属性 说明
rx 椭圆的 x 半径
ry 椭圆的 y 半径
cx 椭圆中心的 x 位置
cy 椭圆中心的 y 位置
<ellipse cx="25" cy="25" rx="25" ry="15" />

# 线条 【line】

TIP

线条 Line 绘制直线。它取两个点的位置作为属性,指定这条线的起点和终点位置

[注意]line 相当于只设置路径,需要设置 stroke 属性可以显示出线条

属性 说明
x1 起点的 x 位置
y1 起点的 y 位置
x2 终点的 x 位置
y2 终点的 y 位置
<line x1="10" y1="5" x2="30" y2="50" stroke="#000" />

# 折线【polyline】

TIP

折线 Polyline 是一组连接在一起的直线。它可以有很多的点,折线的所有点位置都放在一个 points 属性中

[注意]如果不将 polyline 的 fill 设置为透明,将会呈现多边形的效果

每个点必须包含 2 个数字,一个是 x 坐标,一个是 y 坐标。所以点列表 (0,0), (1,1) 和(2,2)可以写成这样:“0 0, 1 1, 2 2”

<polyline points="0 0, 20 30, 10 60" fill="transparent" stroke="black" />

# 多边形【polygon】

多边形 polygon 和折线很像,它们都是由连接一组点集的直线构成。不同的是,polygon 的路径在最后一个点处自动回到第一个点。

<polygon points="0 0, 20 30, 10 60" />

# 填充和描边

fill 属性和 stroke 属性。fill 属性设置对象内部的颜色,stroke 属性设置绘制对象线条的颜色

属性 说明
fill 设置对象内部的颜色
stroke 设置绘制对象线条的颜色
fill-opacity 填充色的不透明度
stroke-opacity 边框色的不透明度
stroke-width 描边的宽度
<svg>
  <rect
    x="10"
    y="10"
    width="100"
    height="100"
    stroke="blue"
    fill="purple"
    stroke-width="10"
    fill-opacity="0.5"
    stroke-opacity="0.8"
  />
</svg>

# SVG 文本

# 位置属性

在一个 SVG 文档中,使用<text>元素来设置文本,<text>元素有 x、y、dx、dy 这四个位置属性

属性 说明
x,y 决定了文本在视口中显示的位置
dx,dy 设置文本相对于当前位置的偏移量

DANGER

[注意]如果不设置 y 属性,则文本将不会显示,x 属性可选。默认为 0

[注意]如果 dx 或 dy 的值是多个值(空格隔开),则从第二个值开始,表示文本内字符的间距

<svg style="border:1px dashed #eee">
  <text x="30" y="30">Hello World!</text>
  <text x="30" y="50" dx="10" dy="20">Hello World!</text>
</svg>

<svg style="border:1px dashed #eee">
  <text x="30" y="30" dx="10 10 20 10">Hello World!</text>
</svg>
Hello World! Hello World! Hello World!

# 对齐属性

# 水平对齐

text-anchor用来设置水平对齐,取值包括:start、middle、end 或 inherit

<svg style="border:1px dashed #eee">
  <circle cx="100" cy="50" r="3" fill="red"></circle>
  <circle cx="100" cy="80" r="3" fill="red"></circle>
  <circle cx="100" cy="110" r="3" fill="red"></circle>
  <text x="100" y="50" text-anchor="start">Hello World!</text>
  <text x="100" y="80" text-anchor="middle">Hello World!</text>
  <text x="100" y="110" text-anchor="end">Hello World!</text>
</svg>
Hello World! Hello World! Hello World!

# 垂直对齐

dominant-baseline可以设置垂直对齐,包括以下属性

  • auto
  • use-script
  • reset-size
  • ideographic
  • alphabetic
  • hanging
  • mathematical
  • central
  • middle
  • text-after-edge
  • text-before-edge
  • inherit
Hello World!

# 样式属性

属性 fill 可以给文本填充颜色,属性 stroke 可以给文本描边,也可以引用渐变或图案

字体相关属性,下列每个属性可以被设置为一个 SVG 属性或者成为一个 CSS 声明:font-familyfont-stylefont-weightfont-variantfont-stretchfont-sizefont-size-adjustkerningletter-spacingword-spacingtext-decoration

<svg height="30" style="border:1px dashed #eee">
  <text
    y="20"
    font-size="20px"
    font-weight="bold"
    stroke="red"
    fill="transparent"
  >
    Hello World!
  </text>
</svg>
Hello World!

# tspan

tspan 元素用来标记大块文本的子部分,它必须是一个 text 元素或别的 tspan 元素的子元素。一个典型的用法是把句子中的一个词变成粗体

<text x="10" y="50"> <tspan font-weight="bold">hello </tspan>World!</text>

tspan 新自定义属性

属性 说明
x 设置一个新绝对 x 坐标。它覆盖了默认的当前的文本位置。这个属性可以包含一个数列,它们将一个一个地应用到 tspan 元素内的每一个字符上
dx 从当前位置,用一个水平偏移开始绘制文本。这里,可以提供一个值数列,可以应用到连续的字体,因此每次累积一个偏移类似地,还有 y 和 dy
rotate 把所有的字符旋转一个角度。如果是一个数列,则使每个字符旋转分别旋转到那个值,剩下的字符根据最后一个值旋转
textLength 给出字符串的计算长度。它意味着如果它自己的度量文字和长度不满足这个提供的值,则允许渲染引擎精细调整字型的位置
<svg height="30" style="border:1px dashed #eee">
  <text x="10" y="20">
    Hello
    <tspan x="100" dx="0 10 10 10" rotate="30" font-weight="bold">World!</tspan>
  </text>
</svg>
HelloWorld!

# textPath

该元素利用路径文本 textPath 的 xlink:href 属性取得一个任意路径,把字符对齐到路径,于是字体会环绕路径、顺着路径走

DANGER

该元素利用路径文本 textPath 的 xlink:href 属性取得一个任意路径,把字符对齐到路径,于是字体会环绕路径、顺着路径走

<svg width="300" height="80">
  <path
    id="my_path"
    d="M 20,20 C 50 50, 160 50, 160 20"
    stroke="#333"
    fill="none"
  />
  <text>
    <textPath xlink:href="#my_path">Hello World!</textPath>
  </text>
</svg>
Hello World!

DANGER

  • 使用 textPath 后,text 元素的 x 和 y 属性的含义有所改变
  • x 路径位置
  • y 无效
  • textPath 只有一个 startOffset 属性,用来确定排列起始位置

# SVG 路径

# path 字符串

路径(path)是一个非常强大的绘图工具,可以用 path 元素绘制矩形(直角矩形或者圆角矩形)、圆形、椭圆、折线形、多边形,以及一些其他的形状,例如贝塞尔曲线、2 次曲线等曲线

SVG 路径最常用的属性是 d 属性,即 path 字符串,用来定义 path 元素的路径形状

属性 d 的值是一个“命令+参数”的序列,每一个命令都用一个关键字母来表示。

Path 命令有如下规律

  • 1、区分大小写:每一个命令都有两种表示方式,一种是用大写字母,表示采用绝对位置。另一种是用小写字母,表示采用相对位置
  • 2、最后的参数表示最终要到达的位置
  • 3、上一个命令结束的位置就是下一个命令开始的位置
  • 4、命令可以重复参数表示重复执行同一条命令
  • 5、因为属性 d 采用的是用户坐标系统,所以不需标明单位

# 直线路径

5 个画直线的命令

  • M (moveto):需要两个参数(x 轴和 y 轴坐标,移动到的点的 x 轴和 y 轴的坐标
  • L (lineto):需要两个参数(x 轴和 y 轴坐标),它会在当前位置和最新的位置(L 前面画笔所在的点)之间画一条线段。
  • H (horizontal lineto):一个参数,标明在 x 轴移动到的位置,绘制水平线
  • V (vertical lineto):一个参数,标明在 y 轴移动到的位置,绘制垂直线
  • Z (closepath):从当前点画一条直线到路径的起点

TIP

“Move to”命令,M 需要两个参数,分别是需要移动到的点的 x 轴和 y 轴的坐标。假设,画笔当前位于一个点,在使用 M 命令移动画笔后,只会移动画笔,但不会在两点之间画线。因为 M 命令仅仅是移动画笔,但不画线。所以 M 命令经常出现在路径的开始处,用来指明从何处开始画

<svg width="100" height="100" style="border:1px dashed #eee">
  <!-- L x y  或 l dx dy -->
  <text x="20" y="50">M L 命令</text>
  /
  <path d="M 10 50 L 90 50" fill="none" stroke="#333"></path>
</svg>

<svg width="100" height="100" style="border:1px dashed #eee">
  <!-- H x 或  h dx-->
  <text x="20" y="50">M H 命令</text>
  <path d="M 10 50 H 90" fill="none" stroke="#333"></path>
</svg>

<svg width="100" height="100" style="border:1px dashed #eee">
  <!-- V y 或 v dy -->
  <text x="0" y="20">
    <textPath xlink:href="#_mv">M V 命令</textPath>
  </text>
  <path id="_mv" d="M 50 10 V 90" fill="none" stroke="#333"></path>
</svg>

<!-- 闭合路径 Z / z-->
<svg width="100" height="100" style="border:1px dashed #eee">
  <path d="M 10 10 H 90 V 90 Z" fill="none" stroke="#333"></path>
</svg>
M L 命令 M H 命令 M V 命令

# 弧形路径

基本上,弧形可以视为圆形或椭圆的一部分。假设,已知椭圆形的长轴半径和短轴半径,另外已知两个点(它们的距离在圆的半径范围内),这时有两个路径可以连接这两个点。每种情况都可以生成出四种弧形。所以,为了保证创建的弧形唯一,A 命令需要用到比较多的参数

A 命令用于画弧形

A rx ry x-axis-rotation large-arc-flag sweep-flag x y
a rx ry x-axis-rotation large-arc-flag sweep-flag dx dy
参数 参数说明
rx ry 椭圆的长半轴 椭圆的短半轴
x-axis-rotation 该段弧 所在椭圆的 x 轴与水平方向的夹角
large-arc-flag 决定弧线是大于还是小于 180 度,0 表示小角度弧,1 表示大角度弧。
sweep-flag 表示弧线的方向,0 表示从起点到终点沿逆时针画弧,1 表示从起点到终点沿顺时针画弧。
x 绘制结束点 x 坐标。
y 绘制点 y 坐标。
<!-- MDN -->
<svg
  width="325"
  height="325"
  xmlns="http://www.w3.org/2000/svg"
  style="border: 1px dashed #eee"
>
  <path
    d="M 80 80
           A 45 45, 0, 0, 0, 125 125
           L 125 80 Z"
    fill="green"
  />
  <path
    d="M 230 80
           A 45 45, 0, 1, 0, 275 125
           L 275 80 Z"
    fill="red"
  />
  <path
    d="M 80 230
           A 45 45, 0, 0, 1, 125 275
           L 125 230 Z"
    fill="purple"
  />
  <path
    d="M 230 230
           A 45 45, 0, 1, 1, 275 275
           L 275 230 Z"
    fill="blue"
  />
</svg>

# 贝塞尔曲线

# SVG 辅助标签

# 超链接

在 SVG 中,可以使用超链接<a>。超链接可以添加到任意的图形上

超链接有如下 3 个常用属性

xlink:href 指定链接地址
xlink:title 指定链接标题
target 指定打开方式
<svg height="100" style="border:1px dashed #eee">
  <a xlink:href="https://juncaihe.com" target="_blank">
    <circle r="20" cx="100" cy="50" stroke="#333" fill="transparent"></circle>
  </a>
  <a xlink:href="https://juncaihe.com" target="_blank">
    <rect
      x="150"
      y="25"
      width="80"
      height="50"
      stroke="#333"
      fill="transparent"
    ></rect>
  </a>
</svg>

# 辅助标签

四个常用的辅助标签:<g><use><symbol><defs>

# g

<g>是一个分组(容器)标签,用来组合元素。可以设置一组元素的属性

DANGER

由于<g>是一个通用的分组标签,可以包含任何形状,因此其只能设置所有形状都有的属性, 包括 stroke、fill 等。由于 cx、cy 是圆特有的属性,所以无法在<g>上设置

<!-- <svg height="200" style="border:1px dashed #eee"> 
    <circle r="20" cx="60" cy="60" fill="#42b983" stroke="#333" stroke-width="2"></circle>
    <circle r="20" cx="150" cy="90" fill="#42b983" stroke="#333" stroke-width="2"></circle>
    <circle r="20" cx="190" cy="120" fill="#42b983" stroke="#333" stroke-width="2"></circle>
    <circle r="20" cx="100" cy="100" fill="#42b983" stroke="#333" stroke-width="2"></circle>
  </svg> -->

<!-- 只需要改一处属性 组内元素对应属性也全改变-->
<svg height="200" style="border:1px dashed #eee">
  <g fill="#42b983" stroke="#333" stroke-width="2">
    <circle r="20" cx="60" cy="60"></circle>
    <circle r="20" cx="150" cy="90"></circle>
    <circle r="20" cx="190" cy="120"></circle>
    <circle r="20" cx="100" cy="100"></circle>
    <rect x="60" y="150" width="100" height="30"></rect>
  </g>
</svg>

# defs

TIP

SVG 允许定义以后需要重复使用的图形元素。 建议把所有需要再次使用的引用元素定义在 defs 元素里面。这样做可以增加 SVG 内容的易读性和可访问性。 在 defs 元素中定义的图形元素不会直接呈现

<svg width="100px" height="100px">
  <defs>
    <linearGradient id="Gradient01">
      <stop offset="20%" stop-color="#39F" />
      <stop offset="90%" stop-color="#F3F" />
    </linearGradient>
  </defs>
  <rect x="10" y="10" width="60" height="10" fill="url(#Gradient01)" />
  <circle r="20" cx="40" cy="50" fill="url(#Gradient01)"></circle>
</svg>

# use

TIP

use元素在 SVG 文档内取得目标节点,并在别的地方复制它们。它的效果等同于这些节点被深克隆到一个不可见的 DOM 中,然后将其粘贴到 use 元素的位置

因为克隆的节点是不可见的,所以当使用 CSS 样式化一个 use 元素以及它的隐藏的后代元素的时候,隐藏的、克隆的 DOM 不能保证继承 CSS 属性,除非明文设置使用 CSS 继承。

出于安全原因,一些浏览器可能在 use 元素上应用同源策略,还有可能拒绝载入 xlink:href 属性内的跨源 URI。

<svg
  height="100"
  xmlns="http://www.w3.org/2000/svg"
  xmlns:xlink="http://www.w3.org/1999/xlink"
>
  <style>
    .classA {
      fill: red;
    }
  </style>
  <defs>
    <g id="Port">
      <circle style="fill:inherit" r="10" />
    </g>
  </defs>

  <text y="15">black</text>
  <use x="50" y="10" xlink:href="#Port" />
  <text y="35">red</text>
  <use x="50" y="30" xlink:href="#Port" class="classA" />
  <text y="55">blue</text>
  <use x="50" y="50" xlink:href="#Port" style="fill:blue" />
</svg>
black red blue

# symbol

TIP

symbol元素用来定义一个图形模板对象,它可以用一个<use>元素实例化。symbol元素对图形的作用是在同一文档中多次使用,添加结构和语义,从而提升了可访问性

一个symbol元素本身是不呈现的。只有symbol元素的实例(亦即,一个引用了 symbol 的 <use>元素)才能呈现

一个<symbol>元素可以有 preserveAspectRatio 和 viewBox 属性。而<g>元素不能拥有这些属性。因此相比于在<defs>元素中使用<g>的方式来复用图形,使用<symbol>元素也许是一个更好的选择

<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
  <symbol id="sym01" viewBox="0 0 150 110">
    <circle cx="50" cy="50" r="40" stroke-width="8" stroke="red" fill="red" />
    <circle
      cx="90"
      cy="60"
      r="40"
      stroke-width="8"
      stroke="green"
      fill="white"
    />
  </symbol>
  <use xlink:href="#sym01" x="0" y="0" width="100" height="50" />
  <use xlink:href="#sym01" x="0" y="50" width="75" height="38" />
  <use xlink:href="#sym01" x="0" y="100" width="50" height="25" />
</svg>

# SVG视野

# 视窗✨

SVG的属性width、height来控制视窗的大小,也称为SVG容器

# 世界🔮

SVG里面的代码,就是对SVG世界的定义 (显示内容)

# 视野🎦

世界是无穷大的,视野是观察世界的一个矩形区域。视窗内得可视区域 如下图所示

TIP

世界不可变,而视野是可以改变的。在SVG中,提供了viewBoxpreserveAspectRatio属性来控制视野

# viewbox

  • viewBox属性允许指定一个给定的一组图形伸展以适应特定的容器元素
  • viewBox属性的值是一个包含4个参数的列表 min-x, min-y, width and height, 以空格或者逗号分隔开, 在用户空间中指定一个矩形区域映射到给定的元素

SVG 可视区域效果

<!-- svg画布大小 === 可视范围 -->
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 200 200" style="background-color: green;">
  <rect x="0" y="0" width="50" height="50" fill="red"/>
</svg>
<!-- svg画布大小 < 可视范围 -->
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 400 400" style="background-color: green;">
  <rect x="0" y="0" width="50" height="50" fill="red"/>
</svg>
<!-- svg画布大小 > 可视范围 -->
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 100 100" style="background-color: green;">
  <rect x="0" y="0" width="50" height="50" fill="red"/>
</svg>

TIP

svg画布大小 > 可视范围

如果不看viewBox,一定会觉得诧异。SVG尺寸明明有200*200像素,而小小的<rect>大小只有其50*50,但是显示出来的图形占据了大量的区域

SVG里面的图形等元素的尺寸是依据viewBox的width、height设置来布局的。最终,再把viewBox的尺寸放大到视窗的尺寸大小来显示

# 结论

世界是无穷大的。viewBox的尺寸设置的越大,即视野越大,则可显示的世界的区域就越大。由于视窗大小是固定的,因此,SVG内部元素尺寸看上去就越小。反之亦然

# preserveAspectRatio

上面的例子,SVG的宽高比正好和viewBox的宽高比是一样的,都是4:3。显然,实际应用viewBox不可能一直跟viewport相同比例。此时,就需要preserveAspectRatio出马了,此属性也是应用在<svg>元素上,且作用的对象都是viewBox

preserveAspectRatio属性的值为空格分隔的两个值组合而成。第一个值表示,viewBox如何与SVG viewport对齐;第二个值表示,如何维持高宽比(如果有)

其中,第1个值又是由两部分组成的。前半部分表示x方向对齐,后半部分表示y方向对齐

值      含义
xMin    viewport和viewBox左边对齐
xMid    viewport和viewBox x轴中心对齐
xMax    viewport和viewBox右边对齐
YMin    viewport和viewBox上边缘对齐。注意Y是大写。
YMid    viewport和viewBox y轴中心点对齐。注意Y是大写。
YMax    viewport和viewBox下边缘对齐。注意Y是大写。

然后,把x和y进行组合,比如xMinYMin、xMidYMin

preserveAspectRatio属性第二部分的值支持下面3个

值      含义
meet    保持纵横比缩放viewBox适应viewport
slice   保持纵横比同时比例小的方向放大填满viewport
none    扭曲纵横比以充分适应viewport

WARNING

  • [注意]preserveAspectRatio属性第二部分的值设置为none时,第一部分的值必须为空,否则报错
  • 如果不设置preserveAspectRatio属性,默认是xMidYMid、meet属性
Document

可视区域效果 + preserveAspectRatio + viewBox

preserveAspectRatio - align: meetOrSlice:
viewBox - x: y: width: height:

# SVG 坐标系统及图形变换

# SVG 坐标系统及图形变换

# SVG 图案

# SVG 裁切和蒙版

# SVG 动画

# SVG 基本操作 API

Last Updated: 8/6/2022, 12:22:56 PM