最近项目在做自适应,使用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。
viewport 和 viewbox 的关系是,viewport 决定了 SVG 图像在网页中的显示大小,而 viewbox 决定了 SVG 图像的内部大小和坐标系。当 viewport 和 viewbox 的比例不一致时,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可以自适应,视口保持和画布大小一致。
当 viewport 和 viewbox 的比例不一致时,这时就会存在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 属性的值可以是以下两种形式之一:
- preserveAspectRatio="none":不保持宽高比例,即强制拉伸 SVG 图形以适应容器大小。
- 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
- 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
被裁减的矩形
以上这些内容足以满足项目使用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组件,这样基本可以实现图标自由。