如何縮放SVG

cunqu9743發表於2020-06-26

以下是Amelia Bellamy-Royds的來賓帖子。 作為SVG Essentials的合著者和即將出版的《 將SVG與CSS3和HTML5結合使用》的作者,Amelia在SVG方面擁有豐富的經驗。 我和Amelia都將在即將到來的RWD峰會上就SVG發表演講! 在這裡,她分享了擴充套件SVG的史詩指南,涵蓋了您可能要執行的所有方法。 它幾乎不像縮放柵格圖形那樣簡單,但是那樣很好,因為它帶來了有趣的可能性。

您已做出決定。 您終於要做到了。 今年,您將開始在Web設計中使用SVG 。 您在Inkscape中建立了精美的標題徽標,然後將其吐出的SVG程式碼複製並貼上到WordPress標題檔案中。 當然,您不會因為總是使用響應式設計而放棄去年的解析度,因此您設定svg.banner { width: 100%; height: auto; } svg.banner { width: 100%; height: auto; } svg.banner { width: 100%; height: auto; } ,並認為您已設定好。

除非您在測試瀏覽器中開啟網頁,然後發現其中一些在影像的上方和下方都留有巨大的空白塊,而另一些則將其裁剪得太短。

SVG代表可縮放向量圖形。 因此,縮放SVG應該很容易,對吧? SVG倡導者一直以來都在說SVG在任何大小上看起來都不錯嗎? 是的,但事實並非如此。 SVG在任何規模上都看起來不錯,但是它可以以多種不同的方式進行擴充套件,以至於它只能按照您想要的方式執行,這會使SVG初學者感到困惑。 瀏覽器只是最近才開始採用標準方法來調整嵌入式SVG內容的大小,這無濟於事。

SVG不是(只是)影像

縮放SVG如此困難的部分原因是因為我們對影像如何縮放有一定的瞭解,並且SVG的行為方式不同。

JPG,PNG和GIF之類的光柵影像具有明確定義的尺寸。 影像檔案描述了瀏覽器應如何在一定畫素寬和一定畫素高的網格中著色。 一個重要的副作用是,光柵影像具有明確定義的寬高比寬高比

您可以強制瀏覽器以不同於其固有高度和寬度的大小來繪製光柵影像,但是如果將其強制為不同的寬高比,則事情將變得失真。 出於這個原因,自網路早期以來,就支援auto縮放影像:設定高度寬度,然後瀏覽器調整其他尺寸,以使縱橫比保持恆定。

看到筆影像縮放基本由無肢貝拉米-羅伊茲( @AmeliaBR上) CodePen

相反,SVG影像可以以任何畫素大小繪製,因此它們不需要明確定義的高度或寬度。 而且它們並不總是具有明確定義的寬高比。 如果希望SVG縮放以適合您提供的尺寸,則需要顯式提供此資訊(以及更多資訊)。

如果您不這樣做,SVG將根本無法擴充套件。 下面的示例使用嵌入式SVG,在不更改繪製圖形大小的情況下,調整元素的尺寸(虛線):

見筆無標SVG被阿梅利亞貝拉米-羅伊茲( @AmeliaBR上) CodePen

為什麼會這樣呢? 因為SVG並非(僅僅是)影像。 SVG是一個文件。 儘管上面的示例使用了嵌入式SVG,但使用<object><iframe>也很容易。 即使您使用<img>標籤嵌入相同的SVG程式碼,其外觀也將完全相同。

當包含帶有<iframe>HTML檔案時,您不希望在更改框架大小時縮放其中的文字。 與SVG相同。 預設情況下,無論畫布大小如何,都將以程式碼中指定的尺寸繪製它。如果將這些SVG的高度或寬度(或兩者)設定為auto ,會發生什麼? 將使用HTML替換元素的預設大小:寬300px,高150px。 這適用於<img><object><iframe> 。 預設的300×150尺寸也適用於HTML文件中的內聯<svg>元素,但這是HTML5規範中的一個相對較新的共識:預設情況下,其他瀏覽器會將內聯SVG擴充套件為視口的完整大小,相當於width: 100vw; height: 100vh; width: 100vw; height: 100vh; —這是直接在自己的瀏覽器標籤中開啟的SVG檔案的預設大小。 Internet Explorer通過使用100%的寬度和150px的高度(用於影像和嵌入式SVG)來縮小差異。

換句話說,即使您認為300×150是理想的影像尺寸(儘管為什麼會這樣?),也不要依賴於HTML中<svg>的預設尺寸。

除了確定SVG的大小,還必須確定希望圖形縮放以適合該大小的方式。 下面,我描述了在最常見的情況下獲取所需比例尺所需的程式碼:

  • 縮放以適合特定大小,而不會扭曲影像
  • 縮放以適合特定大小,並根據需要拉伸或壓縮圖形
  • 縮放以適合可用寬度,同時保持寬高比
  • 以非均勻的方式縮放,以使圖形的某些部分縮放比例與其他部分不同

但首先:如果您想控制SVG的縮放比例,則需要熟悉SVG縮放比例屬性和其他可用工具。

SVG縮放工具箱

其他影像可以縮放,因為瀏覽器知道影像的高度,寬度和縱橫比,並且可以一起調整所有內容。 為SVG提供這​​些屬性是按比例縮放的第一步。 但是,縮放SVG超出了其他影像可能實現的範圍。

heightwidth屬性

乍一看SVG規範將建議頂級svg元素上的heightwidth屬性將隱式設定長寬比,從而使SVG像其他影像一樣縮放。 的確,當您將SVG用作影像時,設定高度和寬度會覆蓋預設尺寸。 但是,這並非易事:

  • 如果使用<img>嵌入SVG,則在大多數瀏覽器中(如果不是Internet Explorer),設定heightwidth將使SVG縮放可預測。 使用CSS,例如img { width: 100%; height: auto; } img { width: 100%; height: auto; } img { width: 100%; height: auto; } ,IE將自動縮放影像區域以保持width:height縱橫比恆定,但不會縮放實際圖形以匹配影像尺寸的比例。
  • 如果您使用<object><embed><iframe>嵌入SVG,則在<svg>上設定高度和寬度不會更改框架的大小; <svg> 。 如果SVG太大,您只會在iframe中獲得滾動條。
  • 如果您使用內聯SVG(即<svg>直接在您HTML5程式碼),那麼<svg>元素具有雙重用途,在網頁內以及在SVG中定義的影像區域。 您使用CSS為SVG設定的任何高度或寬度都將覆蓋<svg>上的height和width屬性。 像svg {width: 100%; height: auto;} svg {width: 100%; height: auto;}將取消您在程式碼中設定的尺寸和寬高比,併為您提供嵌入式SVG的預設高度。 如上所述,根據瀏覽器的不同,該解析度將為150px或100vh。

因此,請忘記heightwidth 。 您實際上並不想設定確切的高度和寬度,而是希望SVG縮放以匹配您在CSS中設定的寬度和/或高度。 您想要的是為影像設定長寬比 ,並使繪圖比例適合。 您需要一個viewBox

viewbox屬性

SVG viewBox在一個小屬性中viewBox了很多魔力。 這是使向量圖形可縮放向量圖形的最後一部分。 viewBox做很多事情:

  • 它定義影像的縱橫比。
  • 它定義瞭如何縮放SVG內部使用的所有長度和座標以適合可用的總空間。
  • 它定義了SVG座標系的原點,即x = 0和y = 0的點。

viewBox<svg>元素的屬性。 它的值是四個數字的列表,用空格或逗號分隔:x,y,寬度,高度。 寬度是SVG程式碼中以使用者座標/ px為單位的寬度,應縮放以填充繪製SVG的區域的寬度(SVG語言中的視 )。 同樣,高度是應該縮放以填充可用高度的px /座標數。 即使您的SVG程式碼使用其他單位,例如英寸或釐米,它們也將被縮放以匹配viewBox建立的整體比例。

x和y數字指定比例縮放的viewBox座標系中的座標,該座標用於SVG視口的左上角。 (座標從左到右和從上到下增加,與在JavaScript中標識頁面位置相同)。 為了進行簡單縮放,可以將兩個值都設定為0。但是,x和y值有兩個用途:建立一個以圖形為中心的原點的座標系(這可以使定義和變換形狀更加容易),或者裁剪比原始定義更緊的影像。

一些示例viewBox值:

  • viewBox="0 0 100 100" :定義一個座標系,其寬度為100個單位,高度為100個單位。 換句話說,如果SVG包含一個以圖形為中心且半徑為50px的圓,則即使該圖片以全屏顯示,它也會填滿SVG影像的高度或寬度。 如果您的SVG包含一個height="1in"的矩形,它也會幾乎填滿整個螢幕,因為CSS中1英寸= 96畫素,所有長度都將按比例縮放。
  • viewBox="5 0 90 100" :幾乎相同的檢視,但在左右兩側裁剪了5%,因此總寬度= 90個單位,而x座標在左側= 5。
  • viewBox="-50 -50 100 100" :具有相同比例的檢視,但現在左上角已指定座標(-50,-50)。 這意味著右下角的座標為(+50 +50)。 在(100,100)處繪製的任何形狀都將遠離螢幕。 如果要繪製一個完全填滿影像區域的圓,則該圓將以(0,0)為中心。

viewBox新增到<svg> (預設情況下,Inkscape和Illustrator之類的編輯器會新增它)後,您可以將該SVG檔案用作影像或內聯SVG程式碼,並且可以完美縮放以適合任何大小你給它。 但是,它仍然無法像其他任何影像一樣縮放。 預設情況下,如果您提供的尺寸與寬高比不匹配, 不會拉伸或變形 。 相反,將調整比例,以保留程式碼中定義的寬高比。

preserveAspectRatio屬性

viewBox屬性具有一個補充, preserveAspectRatio 。 除非存在用於定義影像縱橫比的viewBox否則它無效。 當有viewBox時, preserveAspectRatio描述瞭如果viewBox的縱橫比與視口的縱橫比不匹配時如何縮放影像。 在大多數情況下,預設行為效果很好:將影像縮放到恰好適合高度和寬度,並且將其居中放置在任何額外空間內。

就像viewBox一樣, preserveAspectRatio在單個屬性中具有大量資訊。 可以使用preserveAspectRatio="xMidYMid meet"顯式設定預設行為。 第一部分, xMidYMid告訴瀏覽器在x和y方向xMidYMid縮放後的viewBox區域居於可用視口區域的中心。 您可以替換MidMinMax對齊圖形平齊一方或另一方。 但是,請注意駝峰大寫:SVG是XML,因此區分大小寫。 x是小寫字母,而Y是大寫字母。

預設preserveAspectRatio後半部分, meet ,是告訴瀏覽器縮放圖形直到恰好適合高度和寬度的部分。 CSS背景圖片的等效background-size: contain;background-size: contain; 。 SVG的替代值是slice (相當於background-size: cover; )。 slice值將縮放影像以適合更大的尺寸,並切掉多餘的部分。 除此以外,它並不一定要削減掉多餘的部分。 這取決於overflow屬性的值。

(旁註:如果希望每個影像都可以在其給定的尺寸上居中,而不是被拉伸或變形, 則新的object-fit CSS屬性可讓您對其他影像型別執行相同操作 。)

preserveAspectRatio="none"選項,以使SVG完全像光柵影像一樣縮放(但解析度要好得多),拉伸或壓縮以適合您提供的高度和寬度。

如何縮放SVG以適合特定大小(不使影像失真)

可能最常見的要求是使SVG圖示比例尺適合特定的大小,而不會失真。 儘管您可以使用preserveAspectRatio來調整對齊方式,但是viewBox屬性實際上是您所需要的。

如前所述,如果要在圖形編輯器中建立SVG,則它可能已經包含了viewBox。 但是,您可能需要調整viewBox以使定位恰到好處。 在其餘的示例中,已為該金罐圖形提供了viewBox="0 0 60 55" 。 在它周圍留出一些額外的空間; 要建立一個裁剪圖示,可以使用viewBox="4.5 1.5 51 49" 。 以下示例還顯示了預設的preserveAspectRatio的效果,該效果將圖形居中放置在所提供的空間中:

參見Pen Normal SVG縮放,並在 CodePen上使用Amelia Bellamy-Royds( @AmeliaBR )的viewBox

如何縮放SVG以適合可用寬度(並調整高度以匹配)

帶有viewBox SVG可以縮放以適合您提供的高度和寬度。 但是自動調整大小呢? 對於光柵影像,您可以設定width height ,並使另一個比例匹配。 SVG可以做到嗎?

可以,但是變得複雜。 有兩種不同的方法可供選擇,具體取決於您包含SVG的方式。

選項1:使用圖片自動調整大小

當SVG檔案具有viewBox並將其嵌入<img> ,瀏覽器將(幾乎總是)縮放影像以匹配viewBox定義的寬高比。

CodePen檢視 Amelia Bellamy-Royds( @AmeliaBR )的Pen Auto-Scaling SVG影像

但是,Internet Explorer仍然是SVG的禍根。 儘管通常正常工作,但我使用display: table-cell在本示例的早期版本中佈置了數字,並且IE以怪異的方式扭曲了影像。

如果完全自動調整影像大小,則Internet Explorer將應用標準的預設300×150大小。 但是,其他瀏覽器將應用{ width: 100%; height: auto; } { width: 100%; height: auto; } { width: 100%; height: auto; }預設如果影像具有viewBox ; 此行為未在任何規範中定義。

回顧一下:要自動縮放用作<img> SVG,

  1. 設定一個viewBox屬性。
  2. 設定為高度或寬度的至少一個
  3. 如果您想支援Internet Explorer,請不要將其放在表格佈局中。

選項2:使用CSS背景圖片和padding-bottom Hack

在大多數情況下,將SVG用作CSS背景圖片的方式與<img>使用SVG的方式幾乎相同(但還有一個額外的好處,即可以為舊版瀏覽器定義柵格後備)。 較舊的瀏覽器在將影像轉換為光柵後而不是之前(即畫素化)縮放影像時,存在一些錯誤,但是在大多數情況下, viewBox就是您所需要的。

但是,自動調整大小不是CSS背景圖片的選項; 畢竟,該影像應該位於元素HTML內容之後。 如果您希望元素與要使用的影像的長寬比完全匹配,則將不得不對其進行一些修改。

有一定數量CSS屬性,可讓您根據可用寬度調整基於高度的屬性。 如果將block-layout元素的borderpaddingmargin設定為百分比值,則即使相對於頂部底部邊框,padding和margin,百分比也將相對於容器的可用寬度進行計算。

預期的目的是即使高度是自動的,也要建立均勻大小的邊框和填充。 但這不是重點。 出於我們的目的,關鍵是您可以與寬度成比例地調整元素的總高度。 換句話說,您可以控制縱橫比。 要建立寬度為100%的<div> ,該寬度與您用作背景的影像的4:3長寬比完全匹配,可以使用:

.ratio4-3 {
 width: 100%;
 background-image: url(image-with-4-3-aspect-ratio.svg);
 background-size: cover;
 height: 0;
 padding: 0; /* reset */
 padding-bottom: calc(100% * 3 / 4);
}

注意事項:

  • 要獲得所需高度(以可用寬度的百分比表示),請將寬度百分比乘以所需高度係數,再除以所需寬度係數。
  • 如果要支援不支援calc()瀏覽器,則需要自己(或使用CSS前處理器)進行數學calc()
  • 如果預設情況下將每個元素設定為box-sizing: border-box ,則必須將其重新設定為使用box-sizing: content-box 。 我們希望它是height: 0畢竟是height: 0 填充。
  • 由於IE5中的問題,使用padding-bottom屬性代替了padding-top屬性。 儘管您可能並不擔心支援IE5,但您還是應該保持一致。 畢竟,這被稱為padding-bottom hack。

對於黃金罐影像,長寬比為60:55,底部填充為92%。 實際上,它看起來像這樣:

請參見CodePen上的Ascalia Bellamy-Royds( @AmeliaBR )將Pen 縮放<div>以匹配影像長寬比

選項3:使用嵌入式SVG和最新的Blink / Firefox瀏覽器

SVG影像很好,但是在許多情況下,您會更喜歡使用嵌入式SVG。 內聯SVG減少了HTTP請求的數量,允許使用者互動,並且可以通過您的主網頁中CSS進行修改。 但是會擴充套件嗎?

如果您使用的是最新的Firefox或Blink瀏覽器,它將使用。 只需在<svg>上設定viewBox ,然後將height或width之一設定為auto 。 瀏覽器將對其進行調整,以使總縱橫比與viewBox相匹配。 美麗。

見筆自動縮放SVG內聯通過阿米莉亞·貝拉米-羅伊茲( @AmeliaBR上) CodePen

但是有可能,這些並不是您需要支援的唯一瀏覽器。

許多瀏覽器(2014年夏季之前釋出的IE,Safari和Opera和Chrome版本)將不會自動調整內建SVG的大小。 如果您未同時指定高度和寬度,則這些瀏覽器將應用其通常的預設大小,如前所述,不同的瀏覽器會有所不同。 影像將縮放以適合該高度或寬度,再次在其周圍保留額外的空白。 同樣,如果同時保留height width auto ,也會發生不一致的情況。

解決方案是再次使用padding-bottom hack自己控制寬高比。 適用於內聯SVG以及<object><iframe>和其他替換元素(如<video>的最簡單方法是使用容器元素。

選項4:在容器上使用padding-bottom Hack

要使用容器<div> ,請向<div>新增類或內聯樣式以為其提供正確的寬高比,就像上面使用背景影像時所做的那樣。 還要設定position: relative對於容器,以便它將成為絕對定位的內容的參考框架。 然後將SVG(或其他物件)設定為position: absolute ,高度和寬度為100%。 需要絕對定位,以便相對於<div>的高度( 包括填充)而不是相對於零高度內容區域來計算百分比。

除非您有很多具有相同長寬比的圖形,否則通常最好宣告內嵌padding-bottom ,以使它就在需要匹配的viewBox旁邊:

<div class="scaling-svg-container" 
   style="padding-bottom: 92% /* 100% * 55/60 */">
  <svg class="scaling-svg" viewBox="0 0 60 55" >
    <!-- SVG content -->
  </svg>
</div>
.scaling-svg-container {
 position: relative; 
 height: 0; 
 width: 100%; 
 padding: 0;
 padding-bottom: 100%; 
 /* override this inline for aspect ratio other than square */
}
.scaling-svg {
 position: absolute; 
 height: 100%; 
 width: 100%; 
 left: 0; 
 top: 0;
}

見筆縮放聯SVG使用軟墊集裝箱被阿梅利亞貝拉米-羅伊茲( @AmeliaBR上) CodePen

容器方法可行,但要付出標記中額外包裝元素的代價。 而且,它也不是通用容器:它必須根據您的SVG所需的確切長寬比進行自定義。 如果您不希望將其擴充套件到完整的100%,事情會變得更加棘手。 您將需要使用另一個包裝器<div>設定所需的寬度和其他定位屬性。 我個人更希望將有關SVG寬高比的所有資訊保留在SVG程式碼本身中。 為此,對於內聯SVG,您需要告訴瀏覽器畫出輪廓線並進入填充。

選項5:在Inline <svg>元素上使用padding-bottom Hack

若要使用padding-bottom hack控制整個<svg>區域的長寬比,則官方高度將(基本上)為零。 使用預設的preserveAspectRatio值,圖形將按比例縮小到無。 相反,您希望圖形可以拉伸以覆蓋您提供的整個寬度,並溢位到您精心設定為正確的寬高比的填充區域上。

再次,我喜歡對padding-bottom寬高比使用內聯樣式,因為需要針對viewBox屬性對其進行自定義。 在下面的示例中,我也將其用於其他樣式屬性,儘管如果您有許多需要相同效果的圖形,則可以使用一個類:

<svg viewBox="0 0 60 55" preserveAspectRatio="xMidYMin slice"
   style="width: 100%; padding-bottom: 92%; height: 1px; overflow: visible">
  <!-- SVG content -->
</svg>

那裡還有其他一些細節:

  • 高度為1px,而不是0,否則SVG可能根本無法繪製(Firefox)或根本無法縮放(Chrome)。
  • 所述preserveAspectRatio使用YMin為垂直取向,從而使所述圖形抵靠的頂整齊地對準<svg>內容區域中,溢位進入底部填充。
  • 儘管“ overflow: visible可能是HTML的預設設定,但需要為SVG顯式設定。

如果您希望SVG縮放到小於100%寬度的某個百分比,請記住相應地調整padding-bottom 。 或使用包裝器<div>設定大小。

見筆縮放SVG內聯使用填充和切片的阿米莉亞·貝拉米-羅伊茲( @AmeliaBR上) CodePen

如何縮放,拉伸和壓縮SVG以完全適合特定大小

儘管通常希望保持寬高比,但有時影像是要拉伸以適合的抽象影像或靈活影像。

選項1:使用百分比

拉伸以適合的一種選擇是對SVG中的所有大小和位置屬性使用百分比值。

見筆Flex的縮放SVG使用百分比由阿梅利亞貝拉米-羅伊茲( @AmeliaBR上) CodePen

關於百分比和SVG的注意事項:

  • 如果您使用百分比來拉伸和壓縮,請不要包含viewBox (儘管您可以指定預設的高度和寬度)。
  • SVG中的某些長度與高度或寬度都沒有明確關聯; 例如,圓的半徑。 如果在這些情況下使用百分比值,則長度將被計算為等效的高度和寬度百分比的幾何平均值(平方和的平方根除以2的平方根)。 這保留了對角線與矩形線的勾股定理關係,但在其他方面有些混亂。
  • SVG中的許多長度不能用百分比指定,最重要的是<path><polygon>元素的座標。

選項2:使用preserveAspectRatio="none"

如果您想靈活地縮放還包括SVG路徑的SVG,則需要使用viewBox加上viewBox preserveAspectRatio="none" 。 這是那條彩虹的稍加幻想的版本,有浮雲 s:

請參閱CodePen上的Amelia Bellamy-Royds( @AmeliaBR )的使用prepareAspectRatio =“ none”的Pen Flex-Scaling SVG

請注意,使用preserveAspectRatio="none" ,所有內容均會被均勻拉伸或壓縮,就像您縮放其他影像型別的比例不均一樣。 這意味著圓圈會變成橢圓形,並且文字也會變形。 為避免這種情況,您需要使用多種縮放方法。

如何分別縮放SVG的各個部分

viewBoxpreserveAspectRatio屬性非常靈活。 一旦你停止SVG的思維只是另一種影像格式,你就可以開始問自己, 希望你的圖形,以規模作為視窗改變大小。

要意識到的重要一點是,您不需要為整個SVG定義單個viewBoxpreserveAspectRatio選項。 相反,您可以使用巢狀的<svg>元素,每個元素都有自己的縮放屬性,以獨立地具有圖形縮放的不同部分。 (您也可以在<symbol><pattern>元素上使用這些屬性,並且可以在SVG中嵌入的其他影像上使用preserveAspectRatio 。)通過這種方法,您可以建立標題圖,該圖可以拉伸以填充寬屏顯示而無需佔用以及過高的高度:

見筆Flex的縮放SVG使用巢狀SVGs被阿梅利亞貝拉米-羅伊茲( @AmeliaBR上) CodePen

翻譯自: https://css-tricks.com/scale-svg/

相關文章