SVG——好用!

649 阅读7分钟

最近项目在做自适应,使用SVG自适应的时候对其中的属性甚是模糊,为了更好的项目中应用也解决自己的疑惑,所以写一篇文章来记录这段探索之旅。

当代网页设计中的矢量图形越来越受欢迎,SVG (Scalable Vector Graphics) 是一种基于 XML 的矢量图形格式,它可以让我们在网页上创建出各种精美的图形和动画效果。在 SVG 中,所有图形都是由一些基本元素组成,包括:

  • <rect>:矩形
  • <circle>:圆形
  • <ellipse>:椭圆
  • <line>:直线
  • <polyline>:折线
  • <polygon>:多边形
  • <path>:路径
  • ...

除了这些基本元素之外,SVG 还支持一些其他元素,比如 <text><image><g> 等等。

SVG 元素可以使用各种属性来控制其外观和行为。以下是一些常用的 SVG 属性:

  • fill:填充颜色
  • stroke:描边颜色
  • stroke-width:描边宽度
  • opacity:不透明度
  • transform:变换
  • ...

show me the code

// 矩形
<svg width="100" height="100">
  <rect x="10" y="10" width="80" height="80" fill="#f00" stroke="#000" stroke-width="1"/>
</svg>
// 圆形
<svg width="100" height="100">
  <circle cx="50" cy="50" r="40" fill="#f00" stroke="#000" stroke-width="1"/>
</svg>
// 折线
<svg width="100" height="100">
  <polyline points="10,20 30,50 60,10" fill="none" stroke="#f00" stroke-width="2"/>
</svg>
// 路劲
<svg width="100" height="100">
  <polyline points="10,20 30,50 60,10" fill="none" stroke="#f00" stroke-width="2"/>
</svg>
// 动画
<svg width="100" height="100">
  <rect x="10" y="10" width="80" height="80" fill="#f00">
    <animate attributeName="x" from="10" to="50" dur="1s" repeatCount="indefinite"/>
  </rect>
</svg>

以上就是一些基础的 SVG 知识和常用的 SVG 元素、属性以及实例。SVG 可以让我们在网页上创建出各种精美的图形和动画效果。

接下来像重点探讨SVG的自适应,以及SVG在组件化中的应用

SVG的自适应

SVG的优势之一可缩放性,SVG的可缩放能力主要通过2个属性来进行设置viewPort和viewbox,同时也会缩放保持宽高比不变。viewport 是 SVG 图像的可见区域,即SVG元素的大小。SVG跟普通html元素一样,也可以通过css来设置width 和 height 属性。而viewbox则是SVG一个属性,‘ viewBox’属性的值是一个由四个数字组成的列表: < min-x > 、 < min-y > 、 < width > 和 < height > ,用空格和/或逗号分隔,我将其理解为画布(坐标系统)。例如,viewbox="0 0 100 100" 表示 viewbox 的左上角为坐标 (0, 0),宽度和高度都为 100。

viewportviewbox 的关系是,viewport 决定了 SVG 图像在网页中的显示大小,而 viewbox 决定了 SVG 图像的内部大小和坐标系。当 viewportviewbox 的比例不一致时,SVG 图像就会被缩放以适应 viewport。viewport不设置时默认值为300px*150px(chrome下),viewbox默认为图形大小。只有设置了viewbox才会产生自适应。

viewport默认值为300px*150px(chrome下), viewBox 属性的默认值为 "0 0 {width} {height}",其中 {width} 和 {height} 分别为 SVG 元素的宽度和高度。 设置viewport,没有设置viewBox时,不会产生自适应,视口和画布大小一致。 不设置viewport,设置viewBox时,svg可以自适应,视口保持和画布大小一致。 当 viewportviewbox 的比例不一致时,这时就会存在2种缩放比, 而svg的缩放时又要保持宽高比不变的,所以怎么取值大还是取小,就需要通过一个新的属性preserveAspectRatio来设置。

scale = max(viewport width / viewBox width, viewport height / viewBox height)
// vs
scale = min(viewport width / viewBox width, viewport height / viewBox height)

preserveAspectRatio 属性的值可以是以下两种形式之一:

  1. preserveAspectRatio="none":不保持宽高比例,即强制拉伸 SVG 图形以适应容器大小。
  2. preserveAspectRatio=" ":保持宽高比例,并指定 SVG 图形如何缩放和定位以适应容器大小。

其中  表示视口与画布的位置关系,可查看align参数列表

  • none:不对齐。
  • xMinYMin:将画布与视口左上角对齐。
  • xMidYMin:将 画布水平中心点与视口的水平中心点对齐,并将 画布的顶部与视口顶部对齐。
  • xMaxYMin:将画布与视口的右上角对齐。
  • xMinYMid:将画布的左侧与视口的左侧对齐,并将画布的垂直中心点与视口的垂直中心点对齐。
  • xMidYMid:将画布与视口的中心点对齐。
  • xMaxYMid:将画布的右侧与视口的右侧对齐,并将画布的垂直中心点与视口的垂直中心点对齐。
  • xMinYMax:将画布与视口左下角对齐。
  • xMidYMax:将画布的水平中心点与视口的水平中心点对齐,并将画布的底部与视口的底部对齐。
  • xMaxYMax:将画布的右下角与视口的右下角对齐。

在宽高比不一致时,有两个可选参数:

  • meet: 保持宽高比并将viewBox缩放为适合viewport的大小,SVG 将优先采纳压缩比较小的作为最终压缩比,meet 是默认参数。
scale = min(viewport width / viewBox width, viewport height / viewBox height)

举例:

<svg width="500" height="200" viewBox="0 0 200 200" style="border: 1px solid #000000"
preserveAspectRatio="xMidYMid meet">
    <rect x="0" y="0" width="200" height="200" style="fill: gold" />
    <rect x="100" y="100" width="100" height="50" style="fill: black" />
</svg>

xMidYMid,将 SVG画布的中心点与视口的中心对齐。meet表示scale取1,那画布的宽高就200*200 截图4_1686048837919转存失败,建议直接上传图片文件

  • slice:保持宽高比并将所有不在viewport中的viewBox剪裁掉,SVG 将优先采纳压缩比较大的作为最终压缩比。
scale = max(viewport width / viewBox width, viewport height / viewBox height)

举例:

<svg width="500" height="200" viewBox="0 0 200 200" style="border: 1px solid #000000" preserveAspectRatio="xMaxYMin slice">
    <rect x="0" y="0" width="200" height="200" style="fill:gold;"/>
    <rect x="50" y="50" width="100" height="50" stroke-width="10" style="stroke: #000000; fill:black;"/>
</svg>

xMaxYMin将画布与视口的右上角对齐,slice表示scale取2.5,所以画布的宽高就是500*500

xMaxYmin-slice_1686048870764转存失败,建议直接上传图片文件

被裁减的矩形

截图3_1686048892262转存失败,建议直接上传图片文件

以上这些内容足以满足项目使用SVG自适应问题,学会这些,SVG便可在项目中大有可为!

SVG在组件化中的应用

先介绍组件化过程中需要用到的几个SVG元素

  • 是 SVG 元素中的一个容器元素,用于定义可重复使用的元素或图形,通常是图案、渐变、滤镜或符号。在 SVG 中,这些定义可以在整个文档中引用,以便在多个元素中重复使用,defs包裹的元素是不显示的只能通过use的方式引用。
  • 元素是 SVG 中的一个容器元素,用于将多个形状或元素分组在一起,以便一起进行变换、剪切、旋转等操作。 元素可以包含任意数量的其他 SVG 元素,例如路径、矩形、文本等,而且可以嵌套使用。
  • 元素也是 SVG 中的一个容器元素,用于定义一个可重复使用的图形符号。symbol 与 g 标签类似,但 symbol 可以拥有一个独立的 viewBox
 <svg width="0" height="0">
      <defs>
        <g id="g-cross">
          <line x1="50" y1="10" x2="50" y2="90" stroke-width="8" stroke="currentColor"></line>
          <line x1="10" y1="50" x2="90" y2="50" stroke-width="8" stroke="currentColor"></line>
        </g>
        <symbol id="s-cross" viewBox="0 0 100 100">
          <line x1="50" y1="10" x2="50" y2="90" stroke-width="8" stroke="currentColor"></line>
          <line x1="10" y1="50" x2="90" y2="50" stroke-width="8" stroke="currentColor"></line>
        </symbol>
      </defs>
    </svg>
<!-- g引用 -->
<svg width="200" height="200">
  <use href="#g-cross" />
</svg>
<!-- symbol引用 -->
<svg width="200" height="200">
  <use href="#s-cross" />
</svg>

在这个栗子中,引用g元素定义的SVG,不能自适应。这样使用者想要实现自适应效果就需要查看定义时的viewBox,而symbol支持viewBox属性,对第三方使用者更为友好。

use使用优化

在组件盛行的今天,一切重复皆可封装为组件,简化使用

<!-- g引用 -->
<svg width="200" height="200">
  <use href="#g-cross" />
</svg>
<!-- symbol引用 -->
<svg width="200" height="200">
  <use href="#s-cross" />
</svg>

对这段代码,可以封装一个Icon组件,定义通过props传递name和样式即可。 这种徒手集成Icon的方式比较低效,需要手动调整svg的参数,对少量图标可以这么做,如果是很多可以参考一些社区方案。这里介绍一种阿里矢量图标库 登录后到找到我的项目

  • 创建 iconfont 项目
  • 上传 SVG 图标
  • 生成 js 库,引用这个外部cdn,不在需要徒手修改参数

结合封装的Icon组件,这样基本可以实现图标自由。