SVG - 基本使用

70 阅读5分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第21天,点击查看活动详情

SVG 全称为(Scalable Vector Graphics),即可缩放矢量图形

SVG 是一种基于XML格式的矢量图,主要用于定义二维图形,支持交互和动画

SVG可以直接嵌入到DOM树中,成为DOM树的一部分

SVG 规范是万维网联盟(W3C) 自 1998 年以来开发的标准,存在版本SVG V1.X 和 SVG V2.x

目前最为常用的版本是SVG V2.x

SVG 图像可在不损失质量的情况下按比例缩放,并支持无损压缩

基于XML的SVG可轻松的用文本编辑器或矢量图形编辑器创建和编辑,并可以直接在浏览器显示

特点

优点

优点说明
扩展性好SVG是矢量图,不是光栅图形(位图),所以SVG放大不会失真
矢量图像是基于矢量的点、线、形状和数学公式来构建的图形,该图形是没有像素的,放大缩小是不会失真
光栅图像是由像素点构建的图像——微小的彩色方块,大量像素点可以形成高清图像,比如照片。图像像素越多,质量越高
灵活性强SVG是基于XML格式的
可结合其它的语言和技术一起使用,包括 CSS、JavaScript、 HTML 和 SMIL
方便执行动画SVG 图像可以使用 JS 、 CSS 和 SMIL 进行动画处理
轻量级与其它格式相比,SVG 图像的尺寸非常小
根据图像的不同,PNG 图像质量可能是 SVG 图像的 50 倍
适合打印SVG是矢量图,所以SVG 图像可以以任何分辨率打印,而不会损失图像质量,且支持压缩
易于编辑只需一个文本编辑器就可以创建 SVG 图像。设计师通常会使用 Adobe Illustrator (AI)等矢量图形工具创建和编辑
例如SEOSVG最终会作为DOM的一部分,所以相比图片而言,搜索引擎更容易读取SVG的语义,并进行收录

缺点

缺点说明
不适合操作高清图片SVG 格式非常适合用于徽标和图标(ICON)等 2D 图形,但不适用于高清图片,不适合进行像素级操作
SVG 的图像无法显示与标准图像格式一样多的细节,因为它们是使用点和路径而不是像素来渲染的
不适合复杂的图片处理SVG 图像变得复杂时,生成的DOM也会变多,因此加载会比较慢

SVG适用场景

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

SVG vs Canvas

SVGCanvas
SVG 是基于矢量的点、线、形状和数学公式来构建的图形,该图形是没有像素的,放大缩小不会失真Canvas 是由一个个像素点构成的图形,放大会使图形变得颗粒状和像素化(模糊)
当 SVG 很复杂时,它的渲染就会变得很慢,因为在很大程度上去使用 DOM 时,渲染会变得很慢Canvas 提供了高性能的渲染和更快的图形处理能力
所以当图像中具有大量元素时,SVG 文件的大小会增⻓得更快(导致DOM变得复杂),而Canvas并不会增加太多
SVG 可以通过JavaScript 和 CSS 进行修改,用SVG来创建动画和制作特效非常方便Canvas只能通过JavaScript进行修改,创建动画得一帧帧重绘
SVG 非常适合显示矢量徽标(Logo)、图标(ICON)和其他几何设计Canvas 主要用于游戏开发、绘制图形、复杂照片的合成,以及对图片进行像素级别的操作,如:取色器、复古照片

初体验

由于 SVG 是一个 XML 文件格式。在编写XML文档时,通常是推荐编写XML声明

虽然这个声明并不是强制性的,但是推荐写上

手动编写svg

v1.x

<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<!--
  <?xml ?> - xml的声明 --- 必须唯一svg文件的第一行
    version - xml的版本 可选值为1.0 和 1.1 (2.0的时候 不需要写version)
    encoding - xml的编码格式 默认值就是UTF-8
    standalone - 一个boolean值,用于指定是否需要外部标记声明(DTD文件)
                - 所谓DTD文件就是xml的格式校对文件,xml的标签是可以自定义的
                - 而浏览器解析svg中的xml格式是需要被预先约定的
                - 所以需要对应的DTD文件 来校对 SVG中对应的xml格式是都正确
      - no 默认值 - 依赖外部声明  需要手动指定外部DTD文件
      - yes - 不依赖外部声明 对应的标记声明 编写在svg文件内部
-->

<!-- 这是最为常见的SVG对应的DTD格式文件 -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">

<!--
  这里是一个SVG 默认svg是行内替换元素 默认的宽高是 300 * 150
  version - 版本 - V2.0 已被废弃
  baseProfile - 作者认为正确渲染内容所需要的最小的 SVG 语言概述 - V2.0已被废弃
              - full - 正常的概述 - 适用于PC
              - basic - 轻量级的概述 - 适用于PDA
              - tiny - 更轻量的概述 - 适用于mobile
  width - 宽
  height - 高
  xmlns - xml namespace 表示为svg开启一个命名空间(模块)
        - 避免svg中的某些属性 和 html中的某些属性冲突
        - 如 title属性 在svg 和 html的head中同时存在,且语义不同
        - 但是 目前如果不写xmlns 浏览器会自动生成对应的xmlns
        - 因为xmlns的值一般是固定的 即为http://www.w3.org/2000/svg
        - 所以在多数情况下,我们并不需要去编写对应的xmlns
-->
<svg
 version="1.0"
 baseProfile="full"
 width="100"
 height="100"
 xmlns="http://www.w3.org/2000/svg"
>
  <rect x="0" y="0" width="100" height="100"></rect>
</svg>

v2.x

<svg
 width="100"
 height="100"
 xmlns="http://www.w3.org/2000/svg"
>
  <rect x="0" y="0" width="100" height="100"></rect>
</svg>

使用JS编写SVG

使用JS脚本来创建SVG时,创建的元素都是需要添加命名空间的,如果不存在对应的命名空间需要使用null来代替

操作SVG的JS api和操作DOM的api是一致的,唯一的区别是在方法名称后边加上了NS{也就是namespace}

方法说明
createElementNS(ns,elname)创建SVG元素
setAttributeNS(ns,attrname,value)给SVG元素添加属性
getAttributeNS(ns,attrname)获取SVG元素上的属性
hasAttributeNS(ns, attrname)判断SVG元素上是否存在某个属性
removeAttributeNS(ns,attname)删除SVG元素上的某个属性
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <script>
    // 定义命名空间
    const xmlns = 'http://www.w3.org/2000/svg'

    // 创建svg元素 --- 使用JS创建svg元素,必须指定命名空间
    const svgEl = document.createElementNS(xmlns, 'svg')
    const rectEl = document.createElementNS(xmlns, 'rect')

    // 属性设置
    svgEl.setAttributeNS(null, 'width', 100)
    svgEl.setAttributeNS(null, 'height', 100)

    rectEl.setAttributeNS(null, 'width', 50)
    rectEl.setAttributeNS(null, 'height', 50)

    // 添加到dom树中
    svgEl.appendChild(rectEl)
    document.body.appendChild(svgEl)
  </script>
</body>
</html>

简单使用

作为image的src使用

<!-- svg会被识别为普通图片 无法进行任何的交互 -->
<img src="./rect.svg" alt="rect">

作为背景使用

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    /* svg会被识别为普通图片 无法进行任何的交互 */
    .svg {
      width: 300px;
      height: 300px;
      background-color: red;
      background-image: url(./rect.svg);
      background-repeat: no-repeat;
    }
  </style>
</head>
<body>
  <div class="svg"></div>
</body>
</html>

直接在html中使用svg源码

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
  </style>
</head>
<body>
  <!-- 此时svg会作为dom的一部分,所以可以进行相应的交互 -->
  <!-- 单独作为svg文件的时候,svg的xmlns属性是不可以省略的 -->
  <!-- 但是如果是直接在html中使用svg源代码,对应的xmlns属性是可以省略的 -->
  <svg
    width="100"
    height="100"
  >
    <rect x="0" y="0" width="100" height="100"></rect>
  </svg>
</body>
</html>