理解SVG中的 viewport,viewBox, preserveAspectRatio


閱讀目錄

一:理解viewport

該屬性表示的是SVG可見區域的大小。或者也可以叫畫布的大小。就好比我們的電腦屏幕,我們只能看到我們電腦屏幕的可視區里面的內容,但是看不到電腦屏幕之外的內容。比如如下代碼:

<svg width="200" height="200" style="border: 1px solid red"></svg>

如上代碼,我們定義了一個svg的畫布,寬度為200px,高度為200px,邊框的顏色為紅色,1像素,實線。因此該代碼的顯示效果在頁面上顯示如下:

如上代碼,我們設置了svg的畫布大小為200px*200px, 如果沒有帶單位的話,該單位默認是 px(像素)。當然也有其他單位:比如:

em: 相對於父元素的字體大小。
ex: 相對於小寫字母的 'x' 的高度(不常用)
px: 像素(在支持css2的圖形系統中,每英寸為96像素)。
pt: 點(1/72英寸)
pc: 12點(1/6英寸)。
cm: 厘米
mm: 毫米
in: 英寸

當然我們還可以指定svg元素的width和height為百分比,當我們的svg元素嵌套在一個div里面去的話,那么它的百分比是相對於外層的div元素的寬度和高度進行計算的。當然如果我們的svg元素為根元素的話,那么它的百分比是相對於窗口的尺寸來計算的。比如如下代碼:

<div style="width:400px;height:400px; border: 1px solid red; ">
  <svg width="20%" height="20%" style="border: 1px solid red;"></svg>
</div>

效果如下所示:

如上圖我們可以看到,我們的svg的寬度和高度為82px; 因為div元素的寬度和高度為400px; 20%的話,20% * 400 = 80px; 再加上2px的邊框,因此一共82px。

如果我們沒有給svg設置寬度和高度的話,它默認的寬度為300px,高度為150px; 如下代碼:

<div style="width:400px;height:400px; border: 1px solid red; ">
  <svg style="border: 1px solid red;"></svg>
</div>

運行的效果如下所示:

理解默認用戶坐標

在svg中有一個默認的坐標系統,其中 水平坐標(x坐標)向右遞增的,垂直坐標(y坐標)是向下遞增的。原點坐標是(0, 0).  該坐標系統類似於我們數學幾何中的坐標。

比如我們現在建立一個200px寬,200px高的視口,然后我們在里面繪制一個矩形,該矩形左上角在坐標(10, 10)的位置,該矩形的寬度為50px, 高度為 50px,基本代碼如下:

<svg style="border: 1px solid red;" width="200" height="200">
  <rect x="10" y="10" width="50" height="50" style="stroke: black; fill:none;"></rect>
</svg>
<div style="width:100px;height:100px;margin-left:10px;background: red;"></div>

運行效果如下:

如上可以看到,我們在svg上繪制了一個小矩形,矩形的寬度為50px,高度也是為50px,然后該矩形的左上角在坐標(10, 10)的位置,因此該坐標點離右邊(x坐標向右是遞增的)和下邊(y坐標向下是遞增的)偏移10px;然后繪制了一個寬度為50px,和高度為50px的小矩形。我們也可以看到我們下面還有一個div元素,設置了 margin-left: 10px; 其實在我們的矩形內部設置了偏移10px,和我們的margin-left 是一個意思的。

二:理解viewBox

viewBox="x, y, w, h"; 該屬性的含義是可視區盒子,即畫布的可視區。

viewport 和 viewBox 分別有自己的坐標系,默認情況下,該兩個坐標系是重合的,即轉換關系是 1:1。

x: 指左上角的坐標,y: 左上角的縱坐標,w: 指寬度,h: 指高度

1. 畫布(viewport)、可視區(viewBox) 的寬度的高度相等情況

比如如下代碼:

<div style="width:100%;display:inline-block;">
  <svg style="border: 1px solid red;" width="400" height="200" viewBox="0,0,400,200">
    <rect x="10" y="10" width="100" height="100" style="stroke: black; fill:none;"></rect>
  </svg>
</div>

如上代碼,svg的畫布大小,寬度為400px,高度為200px,然后使用viewBox屬性定義畫布的可視區的大小寬度也是400px,高度也是200px, 因此該兩個坐標系是重合的,因此我們使用 rect 來創建矩形的話,定義寬度和高度分別為100px,x軸和y軸的偏移位置為10px; 效果如下所示:

2. 畫布不變,可視區的寬度減小的情況

比如如下代碼,可視區的寬度減少100px, 如下代碼所示:

<div style="width:100%;display:inline-block;">
  <svg style="border: 1px solid red;" width="400" height="200" viewBox="0,0,300,200">
    <rect x="10" y="10" width="100" height="100" style="stroke: black; fill:none;"></rect>
  </svg>
</div>
<div style="border: 1px solid red;width:300px;height:200px; margin-left: 60px;"></div>

運行結果如下所示:

如上代碼,畫布大小的寬度是400px,可視區的寬度變成300px; 因此為了使他們的中心點能重合的話,因此需要向右移動的距離 = 400 - 300 / 2 = 50px; 由於 rect 中的x偏移了10px,因此加起來就是偏移了60px了,可以把下面的div作為參照物即可看到。

如下示意圖所示解釋

下面我們繼續把可視區的寬度改為200px; 如下代碼:

<div style="width:100%;display:inline-block;">
  <svg style="border: 1px solid red;" width="400" height="200" viewBox="0,0,200,200">
    <rect x="10" y="10" width="100" height="100" style="stroke: black; fill:none;"></rect>
  </svg>
</div>
<div style="border: 1px solid red;width:200px;height:200px; margin-left: 110px;"></div>

然后我們運行結果如下所示:

可以看到,矩形需要偏移的距離 = 400-200/2 + 10 = 110px; 從下面的div中的margin-left 我們可以看到 偏移110px的時候,才能使 畫布(viewport)和可視區(viewBox)的中心點能夠重合。我們可以繼續看如下示意圖所示:

3. 畫布不變,可視區的高度減小的情況

如下代碼:

<svg style="float:left;border: 1px solid red;" width="200" height="200" viewBox="0,0,200,100">
  <rect x="10" y="10" width="100" height="100" style="stroke: black; fill:none;"></rect>
</svg>
<div style="float:left; margin-left: 20px; border: 1px solid red;width:200px;height:100px;margin-top:60px"></div>

運行結果如下所示:

如上可以看到,矩形向下偏移的距離 = 200 - 100 / 2 + 10 = 60px; 因此我們可以看到我們的下面的div元素 margin-top:60px; 就可以對齊了。

4. 可視區不變,畫布寬度變小

如果可視區不變的話,畫布寬度減少的話,那么矩形也要等比例縮小,比如如下代碼:

<svg style="float:left;border: 1px solid red;" width="100" height="200" viewBox="0,0,200,200">
  <rect x="0" y="0" width="100" height="100" style="stroke: black; fill:none;"></rect>
</svg>
<div style="float:left; margin-left: 20px; border: 1px solid red;width:100px;height:200px;margin-top:50px"></div>

運行結果如下所示:

如上可以看到,矩形本來大小是 100px*100px,現在畫布的寬度改成100px了,那么矩形也變成原來的一半了,至於向下移動距離的計算 = 200 - 100 / 2 = 50px;

5. 可視區不變,畫布的高度變小

可視區不變,畫布高度變小的話,那么矩形也要等比例縮放;如下代碼所示:

<div style="width:100%;display:inline-block;">
  <svg style="float:left;border: 1px solid red;" width="200" height="80" viewBox="0,0,200,200">
    <rect x="0" y="0" width="100" height="100" style="stroke: black; fill:none;"></rect>
  </svg>
</div>
<div style="margin-top:10px;border: 1px solid red;width:200px;height:80px;margin-left:60px"></div>

如上代碼;可視區的高度是畫布的 200/80 = 2.5倍, 因此矩形高度也變成原來的2.5倍分之1. 因此計算公司如下:

200     100 
-——  =  ----  = 40px
80       x

因此矩形的寬度和高度等比例縮放到 40px; 偏移的距離計算方式 = 200 - 80 / 2 = 60px; 因此向右偏移 60px 即可。

如下所示:

也就是說,如果畫布的高度變小的話,那么偏移是向右的,如果畫布的寬度變小,那么偏移是向下的。

6. 可視區寬度和高度大於畫布的寬度和高度

如下代碼:

<svg style="float:left;border: 1px solid red;" width="45" height="135" viewBox="0,0,200,200">
  <rect x="0" y="0" width="100" height="100" style="stroke: black; fill:none;"></rect>
</svg>
<div style="float:left;margin-left:20px;border: 1px solid red;width:45px;height:135px;margin-top:46px"></div>

運行結果如下所示:

如果可視區寬度和高度大於畫布的寬度和高度的話,那么 矩形的寬度和高度的計算方式以 寬度和高度最小的那個來等比例計算,什么意思呢?我們如上的畫布的寬度是45px,高度是135px,那么寬度小於高度,因此需要按照45px來計算,因此計算方式 =

200     100
---  =  ----
45       x 

最后 x = 22.5px 了,由於畫布的寬度小於高度,因此需要向下偏移,那么偏移的距離計算方式 = 135 - 45 / 2 = 45px; 因此向下偏移45px即可,至於上面的div元素 margin-top 為46px,那是因為帶了一像素邊框。

為了驗證這個邏輯,我們可以讓畫布的寬度大於高度,如下代碼所示:

<svg style="border: 1px solid red;" width="145" height="43" viewBox="0,0,200,200">
  <rect x="0" y="0" width="100" height="100" style="stroke: black; fill:none;"></rect>
</svg>
<div style="border: 1px solid red;width:145px;height:43px;margin-top:10px; margin-left: 52px;"></div> 

運行效果如下所示:

矩形的大小計算方式  = 

 200   100
 --- = ---- = 21.5px
  43     x

也就是說 畫布的寬度和高度,那個小就根據那個來縮放比例,現在是高度為 43 x, 43px 小於 寬度 145px, 因此 按照高度 43px 來計算,因此最后我們的矩形的等比例縮放的大小為 21.5px; 那么向右偏移的距離 = 145 - 43 / 2 = 51px 了,同理我們上面的div參考元素 margin-left: 52px, 那是因為邊框有1px;

但是如果如下代碼:

<svg style="border: 1px solid red;" width="145" height="43" viewBox="0,0,200,80">
  <rect x="0" y="0" width="100" height="100" style="stroke: black; fill:none;"></rect>
</svg>
<div style="border: 1px solid red;width:145px;height:43px;margin-top:10px; margin-left: 19px;"></div>

運行效果如下了:

矩形的計算方式 = 

43      x
---  = ---- = 53.75px
80      100

然后偏移的距離 = 80 - 43 / 2 = 37 / 2 = 19px 左右。

三:理解 preserveAspectRatio

該屬性的作用是:它允許我們指定被縮放的圖像相對視口的對齊方式。基本的使用方法如下所示:

preserveAspectRatio = "alignment [meet | slice]"

其中 alignment 指定軸和位置,默認值為 preserveAspectRatio = "xMidYMid meet";

preserveAspectRatio 該屬性是應用在SVG上,且和viewBox屬性配合一起使用的。viewBox屬性值可以指明是否可以等比例縮放(寬高比相同的情況下),以擴展到viewport指定的大小區域中。

該對象第一個參數有如下9個不同的值,分別為如下:

xMinYMin,
xMinYMid,
xMinYMax,

xMidYMin,
xMidYMid,
xMidYMax,

xMaxYMin,
xMaxYMid,
xMaxYMax

如上 x 和 y 表示對齊的軸線,x 表示水平方向對象(往右邊是正數),y表示縱向對象(往下是正數)。min, mid, max 表示對齊的方式。min 是往坐標小的方向對齊,mid是居中對齊,max是往坐標大的方向對齊。

第二個參數有3個值可選,分別為:meet 和 slice 和 none。

meet 的含義是:viewBox保持等比例縮放,整個viewBox在viewport中都是可見的。在滿足2個約束的條件基礎上,盡可能的放大viewBox,當viewport的寬高比和viewBox的寬高比不匹配的時候,那么取寬高比中較小的那個。

slice 的含義是:修剪viewBox保持等比例縮放,整個viewport區域會被viewBox覆蓋。在滿足2個約束的條件基礎之上,盡可能的縮小viewBox,當viewport的寬高比和viewBox的寬高比不匹配時,取寬高縮放比中比較大的那個。

none 的含義是:不強制等比例縮放,盡量以viewBox和viewport以實際的寬高比來縮放圖形,盡量把寬度和高度擴展到這個viewport上。最后的結果就會使圖像變模糊。

我們分別來看下demo:

1. preserveAspectRatio="xMinYMin meet"情況下

強制縮放比例,xMin:viewBox的x軸和viewport的x軸最左邊對齊,YMin:viewBox的y軸和viewport的y軸最左邊對齊。

如下代碼:

<svg 
  style="border: 1px solid red;" 
  width="400" 
  height="200" 
  viewBox="0,0,300,200" 
  preserveAspectRatio="xMinYMin meet"
>
  <rect x="10" y="10" width="100" height="100" style="stroke: black; fill:none;"></rect>
</svg>

運行效果如下:

如上我們看到,當我們設置 xMinYMin 的時候,意味着 x坐標和y軸坐標在原點上(0, 0)。

2. preserveAspectRatio="xMinYMid meet"情況下

強制縮放比例,xMin:viewBox的x軸和viewport的x軸最左邊對齊,YMid:viewBox的y軸和viewport的y軸中點對齊。

<svg 
  style="border: 1px solid red;" 
  width="400" 
  height="200" 
  viewBox="0,0,300,200" 
  preserveAspectRatio="xMinYMid meet"
>
  <rect x="10" y="10" width="100" height="100" style="stroke: black; fill:none;"></rect>
</svg>

運行效果如下:

示意圖如下:

注意: 如上 xMinYMid 和 yMidXMin 效果是不一樣的,最前面的優先級最大,所以它會先以上面的 xMin最左端對齊。

3. preserveAspectRatio="xMinYMax meet"情況下

強制縮放比例,xMin:viewBox的x軸和viewport的x軸最左邊對齊,YMax:viewBox的y軸和viewport的y軸最下邊對齊

如下代碼:

<svg 
  style="border: 1px solid red;" 
  width="400" 
  height="200" 
  viewBox="0,0,300,200" 
  preserveAspectRatio="xMinYMax meet"
>
  <rect x="10" y="10" width="100" height="100" style="stroke: black; fill:none;"></rect>
</svg>

運行效果如下圖所示:

示意圖如下所示:

4. preserveAspectRatio="xMidYMin meet"情況下

強制縮放比例,xMid:viewBox的x軸的中心和viewport的x軸中心對齊,yMin: viewBox的Y軸最上方和viewport的y軸最上方對齊。

如下代碼:

<svg 
  style="border: 1px solid red;" 
  width="400" 
  height="200" 
  viewBox="0,0,300,200" 
  preserveAspectRatio="xMidYMin meet"
>
  <rect x="10" y="10" width="100" height="100" style="stroke: black; fill:none;"></rect>
</svg>

運行效果如下圖所示:

示意圖如下所示:

5. preserveAspectRatio="xMidYMid meet"

強制等比例縮放,xMid:viewBox的x軸中點和viewport的x軸中點對齊,YMid: viewBox的y軸中點 和 viewport的y軸中點對齊。

如下代碼:

<svg 
  style="border: 1px solid red;" 
  width="400" 
  height="200" 
  viewBox="0,0,300,200" 
  preserveAspectRatio="xMidYMid meet"
>
  <rect x="10" y="10" width="100" height="100" style="stroke: black; fill:none;"></rect>
</svg>

運行結果如下所示:

如上代碼,畫布大小的寬度是400px,可視區的寬度變成300px; 因此為了使他們的中心點能重合的話,因此需要向右移動的距離 = 400 - 300 / 2 = 50px; 由於 rect 中的x偏移了10px,因此加起來就是偏移了60px了,可以把下面的div作為參照物即可看到。

如下示意圖所示解釋

如上代碼是我們之前分析的代碼,因為畫布是400px,我們的可視區viewBox的寬度變成300px,但是我們的 preserveAspectRatio 的默認屬性值為:"xMidYMid meet"; 也就是說 x 軸方向是居中的,y軸方向是居中的,因此他們的中心點是相同的。

6. preserveAspectRatio="xMidYMax meet"

強制等比例縮放,xMid:viewBox的x軸中點和viewport的x軸中點對齊,YMax: viewBox的y軸最下方和 viewport的y軸最下方對齊。

代碼:

<svg 
  style="border: 1px solid red;" 
  width="400" 
  height="200" 
  viewBox="0,0,300,200" 
  preserveAspectRatio="xMidYMax meet"
>
<rect x="10" y="10" width="100" height="100" style="stroke: black; fill:none;"></rect>
</svg>

效果如下:

如下示意圖所示解釋

7. preserveAspectRatio="xMaxYMin meet"

強制等比例縮放,xMax:viewBox的x軸和viewport的x軸最右邊對齊,YMax: viewBox的y軸和 viewport的y軸最上方對齊。

代碼:

<svg 
  style="border: 1px solid red;" 
  width="400" 
  height="200" 
  viewBox="0,0,300,200" 
  preserveAspectRatio="xMaxYMin meet"
>
<rect x="10" y="10" width="100" height="100" style="stroke: black; fill:none;"></rect>
</svg>
<div style="width:100%;display: inline-block;">
  <div style="margin-left:110px;border: 1px solid red;width:300px;height:200px;"></div>
</div>

效果如下:

如下示意圖所示解釋

如上代碼;xMax是指 viewBox的x軸和viewport的x軸最右邊對齊,且 YMax: viewBox的y軸和 viewport的y軸最上方對齊。因此如上示意圖,如上面使用了div元素來做參考,margin-left:110px; 因為 畫布的大小是400px,我們的viewBox 是300px; 且rect元素向右移動了10px; 因此一共就是110px了。

8. preserveAspectRatio="xMaxYMid meet"

強制等比例縮放,xMax:viewBox的x軸和viewport的x軸最右邊對齊,YMax: viewBox的y軸和 viewport的y軸中心對齊。

效果和上面第七點是一樣的。這里就不多解釋了。

9. preserveAspectRatio="xMaxYMax meet"

強制等比例縮放,xMax:viewBox的x軸和viewport的x軸最右邊對齊,YMax: viewBox的y軸和 viewport的y軸最下邊對齊。
效果和上面第七點是一樣的。這里就不多解釋了。

10. preserveAspectRatio="xMinYmin slice"

slice 的含義是:修剪viewBox保持等比例縮放,整個viewport區域會被viewBox覆蓋。在滿足2個約束的條件基礎之上,盡可能的縮小viewBox,當viewport的寬高比和viewBox的寬高比不匹配時,取寬高縮放比中比較大的那個。

代碼:

<svg 
  style="border: 1px solid red;" 
  width="400" 
  height="200" 
  viewBox="0,0,300,200" 
  preserveAspectRatio="xMinYMin slice"
>
<rect x="10" y="10" width="100" height="100" style="stroke: black; fill:none;"></rect>
</svg>

效果如下:

如上我們可以看到我們的矩形的寬度和高度變為 133.33px * 133.33px了,為什么呢?那是因為我們的viewport的寬度是400px,我們的viewBox是300px; 因此 400/300 = 1.33, 因此rect的寬度和高度的大小都需要在原來的寬度和高度都乘以1.33來鋪滿我們的viewport(畫布)的。

11 preserveAspectRatio="xMinYMid slice"

代碼:

<svg 
  style="border: 1px solid red;" 
  width="400" 
  height="200" 
  viewBox="0,0,300,200" 
  preserveAspectRatio="xMinYMid slice"
>
<rect x="0" y="0" width="100" height="100" style="stroke: black; fill:none;"></rect>
</svg>

效果如下

示意圖如下所示:

如上所示:xMin 的含義是:viewport(畫布)的x軸與viewBox(可視區)的x軸的最左側對齊,YMid的含義是:viewport(畫布)的Y軸與viewBox(可視區)的Y軸的中心對齊。所以如上所示, 但是由於寬度和高度都等比例放大了,所以結果會向上偏移了。

12. preserveAspectRatio="xMinYMax slice"

代碼:

<svg 
  style="border: 1px solid red;" 
  width="400" 
  height="200" 
  viewBox="0,0,300,200" 
  preserveAspectRatio="xMinYMax slice"
>
  <rect x="0" y="0" width="100" height="100" style="stroke: black; fill:none;"></rect>
</svg>

運行效果如下:

其他的略.....  感覺slice這個屬性沒有理解透。今天先到這....


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM