svg 详解

1,580 阅读7分钟

基本概念和使用

SVG 意为可缩放矢量图形(Scalable Vector Graphics),它是一种用于描述二维矢量图形的 XML 标记语言。与传统的栅格图像不同,SVG 图像可以无限缩放而不会失真,同时也支持交互和动画等特性。

SVG 代码写在根元素 <svg>标签中,表示图形容器的大小和属性。其中,width 和 height 属性指定画布的宽度和高度,viewBox 属性指定可视范围的位置和大小。

SVG 的优点和缺点

  • 优点:
  1. 矢量图形缩放不会失真(像素点数量不变而导致图像出现模糊、锯齿等),而光栅图形(PNG、JPG)缩放会导致失真。
          1. 矢量图形:基于矢量的点、线、形状和数学公式来构建的图形,该图形是没有像素的,放大缩小不会失真。
          2. 光栅图形:由像素点构建的图像—微小的彩色方块,大量像素点可以形成高清图像,比如照片。图像像素越多,质量越高。
  2. 其他优点:灵活(JS 和 CSS 操作);支持动画;轻量(尺寸小);可打印(不会失真);利于 SEO(会被搜索引擎索引);可压缩;易于编辑等。
  • 缺点:
  1. 不适合高清图片制作(非像素级渲染);
  2. SVG 图像变得复杂时,加载会比较慢;
  3. 存在部分浏览器兼容问题。

SVG 的应用场景

  • SVG 非常适合显示矢量徽标(Logo)、图标(ICON)和其他几何设计。
  • SVG 适合应用在需适配多种尺寸的屏幕上展示,因为SVG的扩展性更好。
  • 当需要创建简单的动画时,SVG 是一种理想的格式。
        1. SVG 可以与 JS 交互来制作线条动画、过渡和其他复杂的动画。
        2. SVG 可以与 CSS 动画交互,也可以使用自己内置的 SMIL 动画。
  • SVG 也非常适合制作各种图表(条形图、折线图、饼图、散点图等等),以及大屏可视化页面开发。

标签属性:

1. svg标签属性

height | width | style    高 | 宽 | 定义css属性
viewBox     可视范围
version     定义所使用的 SVG 版本
xmlns         定义 SVG 命名空间

2. circle、ellipse标签属性

cx、cy      圆心坐标
r              半径
rx、ry      垂直半径(椭圆)
fill | fill-opacity | fill-rule     填充色 | 填充透明度 | 图形填充规则
stroke-width | stroke | stroke-opacity     边框宽 | 边框颜色 | 边框颜色透明度

3. line标签属性

x1、y1 | x2、y2     直线起点坐标 | 直线终点坐标

4. rect标签绘制矩形

x、y         矩形的宽度和高度

5. polyline标签绘制折线

points     指定每个端点的坐标,横、纵坐标之间与逗号分隔,点与点之间用空格分隔。

6. path标签绘制路径

d     表示绘制顺序,值为一个长字符串,每个字母表示一个绘制动作,后面跟着坐标
M     移动到(moveto)
L     画直线到(lineto)
Z     闭合路径

例:<path d=" M 18,3 L 46,3 L 46,40 Z "></path>

7. text标签绘制文本

x、y     表示文本区块基线(baseline)起点的横坐标和纵坐标。文字的样式可以用class或style属性指定

8. 更多属性

id     用于引用这个模式的唯一ID,必需
xlink:href     指定所要复制的节点
stroke-linecap       定义不同类型的开放路径的终结(线段两个端点的形状)
stroke-dasharray   绘制虚线,短横线长度,空白长度…

svg 坐标系和单位

坐标系是以左上角为 (0,0) 坐标原点,坐标以像素为单位,x 轴正方向是向右,y 轴正方向是向下。

SVG 坐标系统,分为视口坐标系和用户坐标系,默认以像素为单位,也可以手动指明坐标系的单位。

  • 视口坐标系(视口-viewport):视口坐标系是在视口上建立的坐标系,原点在视口左上角的点(0, 0),x轴正向向右,y轴正向下。

  • 用户坐标系(视图框-viewBox):用户坐标系是建立在 SVG 视口上的坐标系。该坐标系最初与视口坐标系相同——它的原点位于视口的左上角。使用 viewBox 属性,可以修改初始用户坐标系,使其不再与视口坐标系相同。

svg 的 viewBox和width、height

viewBox(左上角横坐标,左上角纵坐标,视口宽度,视口高度):决定可视范围

  1. 可以将viewBox理解为svg画布大小。如果画布变大,里面的形状就显得小;如果画布变小,就有可能将里面的形状裁切。
  2. svg 的widthheight属性设置的是svg这个 html元素 的大小。因为 svg 是矢量图形,所以 svg 的viewBox,包括viewBox中的内容会等比缩放,但并不会变形。当然,widthheight要和viewBox等比例,否则会出现裁切
  3. css 中的widthheight会覆盖 svg 标签本身的widthheight属性,也就是 css 的宽高具有更高的优先级。

在制作svg图形时,可以任意定义viewBox大小,并在其中放置各种形状,这些形状(包括文字等)的定位都相对viewBox。而svg实际应用后的大小,取决于widthheight属性,或者css样式。

svg 预定义元素

常见的 SVG 形状:矩形(rect)、圆形(circle)、椭圆形(ellipse)、线段(line)、折线(polyline)、多边形(polygon)

常见的 SVG 元素还包括:

  • path:路径
  • image:图片
  • text、tspan:文字
  • g 、defs、use、symbols:图形组合和复用

1. <g>-分组

g 是'group'的简写,它能把多个元素放在一组里,对 g 标记实施的样式和渲染会作用到这个分组内的所有元素上。组内的所有元素都会继承 g 标记上的所有属性。用定义的分组还可以使用 use 进行复制使用。

image.png

<svg width="200" height="100" viewBox="0 0 200 100">
  <g fill="pink" id="myClip">
    <circle cx="30" cy="30" r="20"/>
    <circle cx="100" cy="70" r="30"/>
  </g>
</svg>

2. <use>-深度复用

use 标记的作用是能从 SVG 文档内部取出一个节点,克隆它,并把它输出到别处。跟‘引用’很相似,但它是深度克隆。

image.png

<svg width="200" height="200" viewBox='0 0 60 60'>
  <defs>
    <g id="Port">
      <circle style="fill:inherit" r="5"/>
    </g>
  </defs>

  <use x="10" y="10" xlink:href="#Port" style="fill:orange" />
  <use x="30" y="10" xlink:href="#Port" style="fill:pink"/>
  <use x="50" y="10" xlink:href="#Port" style="fill:green"/>
</svg>  

3. <defs>-模板

defs 元素用于预定义一个元素使其能够在 SVG 图像中重复使用,和 g 结合使用。

image.png

<svg width="300" height="300" viewport="0 0 300 300">
  <defs>
    <g id="shape">
        <rect x="25" y="50" width="25" height="25" />
        <circle fill="pink" cx="25" cy="50" r="25" />
        <circle fill="orange" cx="25" cy="50" r="5" />
    </g>
  </defs>

  <use xlink:href="#shape" x="50" y="25" />
  <use xlink:href="#shape" x="150" y="25" />
  <use xlink:href="#shape" x="50" y="100" /> 
  <use xlink:href="#shape" x="150" y="100" /> 
</svg>

4. <symbol>-模板

symbol 标记的作用是定义一个图像模板,相当于 g 和 defs 的结合,可以使用 use 标记实例化它,然后在 SVG 文档中反复使用,这种用法非常的高效。symbol 本身不会输出任何图像,只有使用 use 实例化后才会显示。

image.png

<svg viewBox="0 0 150 150" height="300">
  <symbol id="sym01" viewBox="0 0 150 110">
    <circle cx="50" cy="50" r="40" stroke-width="8" stroke="#2ECC71" fill="#A3E4D7" />
    <circle cx="90" cy="60" r="40" stroke-width="8" stroke="pink" 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>

5. <clipPath> 裁剪

image.png

<svg width="120" height="120" viewPort="0 0 120 120" version="1.1" xmlns="http://www.w3.org/2000/svg">
  <defs>
    <clipPath id="myClip">
      <circle cx="30" cy="30" r="20" />
      <circle cx="100" cy="70" r="30" />
    </clipPath>
  </defs>
  <rect x="10" y="10" width="100" height="100" clip-path="url(#myClip)" fill="pink" />
</svg>

6. <text> 定义文本

image.png

<svg width="200" height="400">
    <!-- y 设置为 0 是看不到的 -->
    <text x="10" y="5" fill="green">hello world !</text>
    <text x="10" y="25" fill="blue">hello world !</text>
    
    <!-- 旋转文本 -->
    <text x="0" y="50" fill="red" transform="rotate(30 20,40)">hello world !</text>
    
    <!-- 文本组 -->
    <text x="10" y="105" style="fill:red;">文本组:
    <tspan x="10" y="125">第一行文字。</tspan>
    <tspan x="10" y="145">第二行文字。</tspan>
    </text>
    
    <!-- 加超链接 -->
    <a xlink:href="https://blog.csdn.net/fuhanghang/article/details/105200772" target="_blank">
        <text x="10" y="170" fill="orange">超链接 !</text>
    </a>
    
    <!-- 按路径渲染文本 -->
    <defs>
        <path id="path1" d="M10,190 a1,1 0 0,0 100,0" />
    </defs>
    <text x="10" y="185" style="fill:red;">
        <textPath xlink:href="#path1">I love SVG I love SVG</textPath>
    </text>
    
    <!-- x 的值定义距离上一个文本的 x 的绝对距离,dx 定义相对距离 -->
    <text x="10 30 50" dx="-10 0 20" y="280 300 280" fill="red">hello world !</text>
    
    <!-- letter-spacing, 定义每一个文本的距离 -->
    <text x="10" y="330" letter-spacing="10" fill="red">hello world !</text>
    
    <!-- text-anchor, 定义文本相对于 x 坐标的处理方法 -->
    <text x="100" y="360" text-anchor="middle" fill="red">hello world !</text>
    <text x="100" y="390" text-anchor="end" fill="red">hello world !</text>
</svg>

svg 渐变

css 样式优先级为:内联的 style > defs 中的 style > 外部 / head 内部 > 属性 fill

SVG中有两种主要的渐变类型:线性渐变和径向渐变。 学习地址:zhuanlan.zhihu.com/p/590107236

1. 线性渐变

线性渐变用 linearGradient 元素来定义,它必须嵌套在 defs 标签中,可以实现水平渐变、垂直渐变或角度渐变。

它有两组坐标属性:x1, y1, x2, y2,用于定义线性渐变的开始位置和结束位置。

  • 当 y1 和 y2 相等,而 x1 和 x2 不等时,就会产生水平渐变。
  • 当 x1 和 x2 相等,而 y1 和 y2 不等时,就会产生垂直渐变。
  • 当 x1 和 x2 不等,y1 和 y2 也不等时,就会产生角度渐变。

image.png

线性渐变的颜色范围可以由两种或多种颜色组成。每种颜色都用一个 stop 标签来指定,一般需要定义两个属性:

  • offset 属性,用于定义渐变颜色的开始和结束位置,属性值是一个描述相对位置的百分比。 (10%)
  • stop-color 属性,用于定义渐变的颜色,取值为任何一个合法的颜色值。

image.png

<svg width="400" height="150">
  <defs>
   <!-- 定义渐变的效果 -->
    <linearGradient x1="0%" y1="0%" x2="100%" y2="0%" id="gradient1">
      <stop offset="0%" stop-color="rgb(255,255,0)"></stop>
      <stop offset="100%" stop-color=" rgb(255,0,0)"></stop>
    </linearGradient>
  </defs>
  <!-- 绘制椭圆形 -->
  <ellipse cx="200" cy="70" rx="85" ry="55" fill="url(#gradient1)"></ellipse>
  <!-- 添加文本 -->
  <text x="150" y="86" fill="#fff" font-size="45">SVG</text>
</svg>

2. 径向渐变

径向渐变应用 radialGradient 元素来定义,也必须嵌套在 defs 标签中。

有几个重要的属性:

  • id 属性,定义了渐变的唯一名称。
  • cx、cy 和 r 属性,定义了最外面的圆。fx 和 fy 属性,定义了最里面的圆。
  • 径向渐变的颜色范围可以由两种或多种颜色组成,和线性渐变一样。

image.png

<svg width="400" height="150" style="background-color: #f2f3f4">
  <defs>
    <radialGradient cx="50%" cy="50%" r="50%" fx="50%" fy="50%" id="gradient2">
      <stop offset="0%" stop-color="rgb(255,255,255)"></stop>
      <stop offset="100%" stop-color="rgb(0,0,255)"></stop>
    </radialGradient>
  </defs>
  <ellipse cx="200" cy="70" rx="85" ry="55" fill="url(#gradient2)"></ellipse>
  <text x="150" y="86" fill="#fff" font-size="45">SVG</text>
</svg>

PS: 修改 radialGradient 标签的 cx,cy,fx,fy 的值,可以调整高光的位置。比如全部修改为30%,高光的位置会移动到左上角。

学习地址:

blog.csdn.net/IAIPython/a…
blog.csdn.net/fuhanghang/…
blog.csdn.net/qq_45801837…
zhuanlan.zhihu.com/p/590107236