一文搞懂SVG的viewBox
属性
MDN介绍viewBox
属性
viewBox 属性允许指定一个给定的一组图形伸展以适应特定的容器元素。
viewBox
属性的值是一个包含 4 个参数的列表 min-x
, min-y
, width
and height
,以空格或者逗号分隔开,在用户空间中指定一个矩形区域映射到给定的元素,查看属性preserveAspectRatio
。
不允许宽度和高度为负值,0 则禁用元素的呈现。
- min-x:定义了viewBox的最小x坐标。
- min-y:定义了viewBox的最小y坐标。
- width:定义了viewBox的宽度。
- height:定义了viewBox的高度。
viewBox的作用
- 缩放:
viewBox
允许SVG
图形在不同的尺寸下进行缩放。无论SVG
容器的尺寸如何变化,内部的图形都会根据viewBox
定义的比例进行缩放。 - 定位:通过设置
min-x
和min-y
,你可以控制SVG
图形在容器中的位置。例如,你可以将图形移动到容器的中心、左上角或其他任何位置。 - 裁剪:
viewBox
还可以用于裁剪SVG
内容,只显示定义区域内的部分。
情况一:已设置svg
固定尺寸
画图理解原理
MDN给出的解释,如果不加以实践,是不能直观的理解viewBox
概念的,实践才是理解概念的唯一标准。
首先,绘制一个正常的矩形1:300*300
,绿色背景,红色边框的矩形,
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
svg {
display: inline-block;
border: 1px solid red;
}
</style>
</head>
<body style="padding: 200px;">
<svg width="300" height="300" >
<rect x="0" y="0" width="300" height="300" fill="#47cc47" />
</svg>
</body>
</html>
运行结果为
然后,绘制矩形2,给svg
增加viewBox
属性,设置viewBox="0 0 300 300"
<body style="padding: 200px;">
<svg width="300" height="300" >
<rect x="0" y="0" width="300" height="300" fill="#47cc47" />
</svg>
<svg width="300" height="300" viewBox="0 0 300 300" >
<rect x="0" y="0" width="300" height="300" fill="#47cc47" />
</svg>
</body>
如果将viewBox
属性的四个值设置为0,0,svgWidth,svgHeight
最终视图显示与矩形1一样,无法理解viewBox
工作原理
接着,绘制矩形3,修改viewBox="0,0,100,100"
<body style="padding: 200px;">
<svg width="300" height="300" >
<rect x="0" y="0" width="300" height="300" fill="#47cc47" />
</svg>
<svg width="300" height="300" viewBox="0 0 300 300" >
<rect x="0" y="0" width="300" height="300" fill="#47cc47" />
</svg>
<svg width="300" height="300" viewBox="0 0 100 100" >
<rect x="0" y="0" width="300" height="300" fill="#47cc47" />
</svg>
</body>
三个矩形无任何差别,肉眼无法分辨出差异。此时打开开发者工具,观察矩形3的尺寸大小。可以很明显的看的矩形3的实际尺寸已经到900,svg中
仅仅显示的是矩形的1/9。这里可以猜测
<body style="padding: 200px;">
<svg width="300" height="300" >
<rect x="0" y="0" width="300" height="300" fill="#47cc47" />
</svg>
<svg width="300" height="300" viewBox="0 0 300 300" >
<rect x="0" y="0" width="300" height="300" fill="#47cc47" />
</svg>
<svg width="300" height="300" viewBox="0 0 100 100" >
<rect x="0" y="0" width="300" height="300" fill="#47cc47" />
</svg>
<svg width="300" height="300" viewBox="0 0 600 600" >
<rect x="0" y="0" width="300" height="300" fill="#47cc47" />
</svg>
</body>
猜想正确,viewBox
的宽高与SVG
内部元素之间的宽高之间的关系弄明白了,尝试着修改一下viewBox
的起始坐标。
接着,绘制矩形5,viewBox="150,150,300,300"
,依然保持宽高为150不变。
<body style="padding: 200px;">
<svg width="300" height="300" >
<rect x="0" y="0" width="300" height="300" fill="#47cc47" />
</svg>
<svg width="300" height="300" viewBox="0 0 300 300" >
<rect x="0" y="0" width="300" height="300" fill="#47cc47" />
</svg>
<svg width="300" height="300" viewBox="0 0 100 100" >
<rect x="0" y="0" width="300" height="300" fill="#47cc47" />
</svg>
<svg width="300" height="300" viewBox="0 0 600 600" >
<rect x="0" y="0" width="300" height="300" fill="#47cc47" />
</svg>
<svg width="300" height="300" viewBox="150 150 300 300" >
<rect x="0" y="0" width="300" height="300" fill="#47cc47" />
</svg>
</body>
根据上图,可见矩形4和矩形5居然一样,但是矩形5的rect
节点宽高是300*300
,而矩形4的是150*150
。
情况二:未设置svg
固定尺寸
如果没有对svg
设置固定尺寸,并且使用了viewBox
属性。这种用法多用于响应式图表。
两坐标均等于0
这里讨论两坐标均等于0(min-x=0,min-y=0)情况,即视图框(viewBox
)的起始点在坐标原点(0,0)
。
在矩形1中,添加一个圆,半径=4。这里矩形完全填充svg
。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style>
html,
body {
height: 100%;
}
svg {
height: 50%;
display: inline-block;
}
</style>
</head>
<body>
<svg viewBox="0 0 100 100">
<rect x="0" y="0" width="100%" height="100%" fill="#47cc47" />
<circle cx="50%" cy="50%" r="4" fill="#3c4acc" />
</svg>
</body>
</html>
当使用相对单位时,如百分比、视觉尺寸,无论是否使用viewBox
,正方形的外观都不会改变。 使用大viewBox
时,圆圈看起来很小。因为它使用用户单位作为r
属性:4远小于viewBox
中设置的100。
为了进行对比,画矩形2。令viewBox="0 0 10 10"
,r=4
不变。
<body>
<svg viewBox="0 0 100 100">
<rect x="0" y="0" width="100%" height="100%" fill="#47cc47" />
<circle cx="50%" cy="50%" r="4" fill="#3c4acc" />
</svg>
<svg viewBox="0 0 10 10">
<rect x="0" y="0" width="100%" height="100%" fill="#47cc47" />
<circle cx="50%" cy="50%" r="4" fill="#3c4acc" />
</svg>
</body>
使用小viewBox
时,圆圈看起来很大。因为它使用用户单位作为r
属性:4仅小于viewBox
中设置的10。所以矩形2中的圆相对于viewBox
尺寸更大。
两坐标有中至少一个小于0
讨论一种特殊情况,当viewBox
起始位置为负数时,请看矩形3。
<body>
<svg viewBox="0 0 100 100">
<rect x="0" y="0" width="100%" height="100%" fill="#47cc47" />
<circle cx="50%" cy="50%" r="4" fill="#3c4acc" />
</svg>
<svg viewBox="0 0 10 10">
<rect x="0" y="0" width="100%" height="100%" fill="#47cc47" />
<circle cx="50%" cy="50%" r="4" fill="#3c4acc" />
</svg>
<svg viewBox="-5 -5 10 10">
<rect x="0" y="0" width="100%" height="100%" fill="#47cc47" />
<circle cx="50%" cy="50%" r="4" fill="#3c4acc" />
</svg>
</body>
可以看到,矩形3已经移到视图的右下角,这是怎么回事呢?
这是因为viewBox
属性则定义了SVG
内部的坐标系统。视图框(viewBox
)的起始点始终为svg的左上角。这个起始点的位置,要相对于屏幕左上角而言。理论见下图。
由于viewBox="-5 -5 10 10"
,x=-5,则视图框的起始点向右移动5的单位;y=-5,视图框的起始点向下移动5个单位。此时视图框的起始点正好位于视口的中心。并且100%仍然解析为10个用户单位的宽度或高度,因此矩形看起来已移动到视口的底部/右角。坐标点0,0位于视口中心时,圆心中点值50%解析为5,这意味着圆心为在视口的底部/右角。为什么显示的是1/4个圆角?因为整个视图大小依然是从0 0 10 10
范围不变,原来svg偏移后得到新的svg;两者之间的交集部分就形成了1/4圆角。这就是viewBox
裁剪SVG
的原理,只显示定义区域内的部分。
有了上面原理,就可以实现任意裁剪的视图,只显示定义区域内的部分。例如显示上半圆部分:
<svg viewBox="0 -5 10 10">
<rect x="0" y="0" width="100%" height="100%" fill="#47cc47" />
<circle cx="50%" cy="50%" r="4" fill="#3c4acc" />
</svg>
原理图如下:
显示左半圆(读者自己画理论图):
<svg viewBox="-5 0 10 10">
<rect x="0" y="0" width="100%" height="100%" fill="#47cc47" />
<circle cx="50%" cy="50%" r="4" fill="#3c4acc" />
</svg>
显示右下角1/4圆(读者自己画理论图):
<svg viewBox="5 5 10 10">
<rect x="0" y="0" width="100%" height="100%" fill="#47cc47" />
<circle cx="50%" cy="50%" r="4" fill="#3c4acc" />
</svg>
配合preserveAspectRatio属性使用
有时候,通常我们使用 viewBox
属性时,希望图形拉伸占据整个视口。在其他情况下,为了保持图形的长宽比,必须使用统一的缩放比例。
preserveAspectRatio
属性表示是否强制进行统一缩放。
对于非标签,preserveAspectRatio
只适用于在同一元素上为 viewBox
提供的值。对于这些元素,如果没有提供属性 viewBox
,则忽略了 preserveAspectRatio
。也就是说,只有设置了viewBox
属性,preserveAspectRatio
才会起作用。
使用:
<svg viewBox="5 5 10 10" preserveAspectRatio="<align> [<meetOrSlice>]" />
align
<align>
属性值表示是否强制统一缩放,当 SVG
的 viewbox 属性与视图属性宽高比不一致时使用。<align>
属性的值一定是下列的值之一:
- none 不会进行强制统一缩放,如果需要,会缩放指定元素的图形内容,使元素的边界完全匹配视图矩形。(注意:如果
<align>
的值是none
,则<meetOrSlice>
属性的值将会被忽略。) - xMinYMin - 强制统一缩放。将 SVG 元素的 viewbox 属性的 X 的最小值与视图的 X 的最小值对齐。将 SVG 元素的 viewbox 属性的 Y 的最小值与视图的 Y 的最小值对齐。
- xMidYMin - 强制统一缩放。将 SVG 元素的 viewbox 属性的 X 的中点值与视图的 X 的中点值对齐。将 SVG 元素的 viewbox 属性的 Y 的最小值与视图的 Y 的最小值对齐。
- xMaxYMin - 强制统一缩放。将 SVG 元素的 viewbox 属性的 X 的最小值 + 元素的宽度与视图的 X 的最大值对齐。将 SVG 元素的 viewbox 属性的 Y 的最小值与视图的 Y 的最小值对齐。
- xMinYMid - 强制统一缩放。将 SVG 元素的 viewbox 属性的 X 的最小值与视图的 X 的最小值对齐。将 SVG 元素的 viewbox 属性的 Y 的中点值与视图的 Y 的中点值对齐。
- xMidYMid (默认值) - 强制统一缩放。将 SVG 元素的 viewbox 属性的 X 的中点值与视图的 X 的中点值对齐。将 SVG 元素的 viewbox 属性的 Y 的中点值与视图的 Y 的中点值对齐。
- xMaxYMid - 强制统一缩放。将 SVG 元素的 viewbox 属性的 X 的最小值 + 元素的宽度与视图的 X 的最大值对齐。将 SVG 元素的 viewbox 属性的 Y 的中点值与视图的 Y 的中点值对齐。
- xMinYMax - 强制统一缩放。将 SVG 元素的 viewbox 属性的 X 的最小值与视图的 X 的最小值对齐。将 SVG 元素的 viewbox 属性的 Y 的最小值 + 元素的高度与视图的 Y 的最大值对齐。
- xMidYMax - 强制统一缩放。将 SVG 元素的 viewbox 属性的 X 的中点值与视图的 X 的中点值对齐。将 SVG 元素的 viewbox 属性的 Y 的最小值 + 元素的高度与视图的 Y 的最大值对齐。
- xMaxYMax - 强制统一缩放。将 SVG 元素的 viewbox 属性的 X 的最小值 + 元素的宽度与视图的 X 的最大值对齐。将 SVG 元素的 viewbox 属性的 Y 的最小值 + 元素的高度与视图的 Y 的最大值对齐。
meetOrSlice
<meetOrSlice>
是可选的,如果提供的话,与 <align>
间隔一个或多个的空格,参数所选值必须是以下值之一:
-
meet(默认值) - 图形将缩放到:
- 宽高比将会被保留
- 整个
SVG
的viewbox
在视图范围内是可见的 - 尽可能的放大
SVG
的viewbox
,同时仍然满足其他的条件。
在这种情况下,如果图形的宽高比和视图窗口不匹配,则某些视图将会超出 viewbox 范围(即
SVG
的viewbox
视图将会比可视窗口小)。 -
slice-图形将缩放到:
- 宽高比将会被保留
- 整个视图窗口将覆盖
viewbox
SVG
的viewbox
属性将会被尽可能的缩小,但是仍然符合其他标准。
在这种情况下,如果 SVG 的
viewbox
宽高比与可视区域不匹配,则viewbox
的某些区域将会延伸到视图窗口外部(即SVG
的viewbox
将会比可视窗口大)。
彩蛋
你以为读完了这篇博客你就弄懂了viewBox吗?不妨一起思考如下问题:
我们的上述例子中viewBox的宽度和高度都是成比例缩放的,假如
SVG会如何缩放画布大小?
如果读取有兴趣可以自行尝试,或者催更我。
iewbox `属性将会被尽可能的缩小,但是仍然符合其他标准。
在这种情况下,如果 SVG 的 `viewbox `宽高比与可视区域不匹配,则 `viewbox `的某些区域将会延伸到视图窗口外部(即 `SVG `的 `viewbox `将会比可视窗口大)。
彩蛋
你以为读完了这篇博客你就弄懂了viewBox吗?不妨一起思考如下问题:
我们的上述例子中viewBox的宽度和高度都是成比例缩放的,假如
SVG会如何缩放画布大小?
如果读取有兴趣可以自行尝试,或者催更我。