大家都知道svg图像之所以能被随意拉伸且保持不失真,主要原因是它能进行矢量缩放,而这种特性主要取决于两个属性,即viewBox和preserveAspectRatio。这 篇文章就svg的这两个属性进行简要讲解。
1、viewBox
viewBox定义了svg中的内容可画的区域(相当于放在视口底下的一块画布),它的语法是:
viewBox = "<min-x> <min-y> <width> <height>"
其中min-x和min-y代表绘画
区域的左上角坐标,width和height代表绘画区域的宽高。
视口指的是svg的实际可见区域,它的大小是由svg元素的width和height两个属性来决定的。注意width、height属性与viewBox值中对应成分的区别,viewBox的值中的成分只表示svg中的内容的理论可画区域的大小,即一块假想画布的大小;这块画布在作完画后会放到svg的实际可见区域(即视口)中,并且会根据另一个属性preserveApsectRatio进行缩放以及放到视口的正确位置,这在之后的内容中会提到。当然,有时候svg元素上不会设置width和height属性,此时svg的实际尺寸应当由包裹它的外部元素来确定;也可能不设置viewBox属性,此时该属 性的值中min-x
、min-y都为0,width、height等于svg元素的实际width、height。
viewBox是一个通用属性,可以在以下元素中使用:
<marker>
<pattern>
<svg>
<symbol>
<view>
接下来的例子为了方便就以<svg>元素为例(这些案例的preserveAspectRatio都为默认值):
①先来看显示设置svg宽高的情况:
<div style="
width: 240px;
height: 100px;
background-color: rgb(127,255,212);
">
<svg viewBox="0 0 50 50"
width="80" height="80"
xmlns="http://www.w3.org/2000/svg"
style="float: left;border: 1px dashed gray;margin-right: 10px;"
>
<circle cx="50%" cy="50%" r="10" fill="red"></circle>
</svg>
<svg viewBox="-10 -10 60 80"
width="120" height="160"
xmlns="http://www.w3.org/2000/svg"
style="float: left;border: 1px dashed gray;"
>
<circle cx="20" cy="30" r="20" fill="gold"></circle>
</svg>
</div>
第一个svg的宽高被设置为80、80,其viewBox被设置为"0 0 50 50",它们的宽高比都为1 : 1,这意味着viewBox定义的区域经缩放会完全拟合(区域的四个角与视口重合)到视口中,不受preserveAspectRatio的影响。容易得出viewBox的缩放率为1.6,并且与视口左上角重合的viewBox左上角的坐标为(0, 0)。在svg中画了一个圆,圆心坐标使用的是百分比值,它表示viewBox中定义的宽或高的百分比,当然,在视口中实际呈现时还要乘上缩放率。这个例子上的圆心坐标在viewBox中即为cx=50*50%=25、cy=50*50%=25。
第二个svg的宽高被设置为120、160,其viewBox被设置为"-10 -10 60 80",它们的宽高比同样都为1 : 1,意味着viewBox的缩放不受preserveAspectRatio的影响。此时,viewBox定义区域的左上角为坐标系的(-10, -10)点,x轴和y轴的长度分别为60、80,viewBox在视口中的缩放率为2。viewBox中的圆其圆心坐标为(20, 30),注意在这里设置坐标为(30, 40)则无法居中,因为左上角的坐标为(-10, -10)而不是(0, 0);再根据坐标系宽高,其右下角的坐标应该为(50, 70)而不是(60, 80)。这个svg的实际视口高度超过了外部div元素的高度但还是完整地显示了出来,要把超出部分隐藏掉可以在div元素上设置css属性overflow: hidden。
②第二种情况,不设置宽高:
<div style="
width: 80px;
height: 80px;
border: 1px dashed gray;
">
<svg viewBox="-10 -10 40 60"
xmlns="http://www.w3.org/2000/svg"
style="background-color: rgba(128, 254, 195, 0.4);"
>
<rect x="0" y="5" width="20" height="35" fill="burlywood"></rect>
</svg>
</div>
这幅图中的svg未设置width和height,只设置了viewBox为"-10 -10 40 60",在其外部有一个宽高分别为80、80的div元素(用虚线框包裹)。可以看到,在未显式设置宽高时,svg视口的宽度取决于外部元素的宽度,宽高比与viewBox的一致(在这里是40 : 60 = 2 : 3)。viewBox经过缩放,它的宽紧随视口的变化,被缩放到与外部div的宽同样大小(在这里是放大80/40=2倍),且宽高比保持不变。
2、
preserveAspectRatio
该属性表示当svg元素中viewBox定义区域的宽高比与视口的宽高比不同时,viewBox定义区域拟合到视口中的方式。该属性的语法为:
preserveAspectRatio = "<align> [<meetOrSlice>] "
它包含两个成分,align表示当viewBox的宽高比不匹配视口的实际宽高比时的对齐方式,它有10个可能值:
- none:对viewBox进行不规则缩放,使其边界矩形完全充满整个视口。设置该值时对<meetOrSlice>的设置无效。
- xMinYMin:对viewBox进行规则缩放,把viewBox的<min-x>与视口的最小x值对齐,把viewBox的<min-y>与视口的最小y值对齐。这相当于把viewBox的左上角与视口的左上角对齐。
- xMidYMin:对viewBox进行规则缩放,把viewBox的中点x值与视口的中点x值对齐,把viewBox的<min-y>与视口的最小y值对齐。这相当于viewBox在视口的顶部居中。
- xMaxYMin:对viewBox进行规则缩放,把viewBox的<min-x>+<width>值与视口的最大x值对齐,把vie