CSS可以用來定義可縮放矢量圖形的樣式和動(dòng)畫,就像CSS定義HTML元素一樣。在本文中,我會(huì)告訴大家一些用CSS定義SVG的前提條件和技術(shù)。(我最近在CSSconf EU和From the Front辦了一個(gè)講座,這篇文章是講座的修正版)
同時(shí)我也會(huì)講一下導(dǎo)出和優(yōu)化SVG、嵌入SVG和每一個(gè)SVG如何影響它的樣式和動(dòng)畫,然后我們?cè)儆懻撚肅SS定義SVG的樣式和動(dòng)畫。
可縮放矢量圖形(SVG)是基于可擴(kuò)展標(biāo)記語言(XML),用于描述二維矢量圖形的一種圖形格式,它們支持交互行為和動(dòng)畫。換句話說,SVG是可以生成形狀和圖形的XML標(biāo)簽,這些形狀和圖形可以像HTML元素一樣實(shí)現(xiàn)交互和動(dòng)畫。
我們可以通過CSS或者Javascript給SVG定義動(dòng)畫和交互行為。在本文中,我們著重討論CSS。
SVG為什么好?為什么你應(yīng)該使用它?其實(shí)答案有很多:
以下是三個(gè)最流行的矢量圖形編輯器:
Adobe Illustrator是Adobe公司收費(fèi)的應(yīng)用程序,它是最受歡迎的編輯器,漂亮的UI和大量的功能使得它成為大多數(shù)設(shè)計(jì)師最喜歡的編輯器。
Inkscape是另一個(gè)免費(fèi)的編輯器,雖然它的UI沒有Illustrator漂亮,但是它仍然具有你所需要的所有功能。
Sketch是只能在Mac OS X上使用的app,雖然它也要收費(fèi),但是它在設(shè)計(jì)師中到處宣傳并收到了歡迎,最近Sketch又推出了許多資源和工具來改善工作流程。
你可以選擇任意編輯器來創(chuàng)建你的SVG。在選擇編輯器、創(chuàng)建SVG之后,在把它嵌入網(wǎng)頁之前,你需要把它從編輯器中導(dǎo)出并進(jìn)行清理。
我會(huì)導(dǎo)出并優(yōu)化在Illustrator中創(chuàng)建的SVG,除了Illustrator特定的一些選項(xiàng),其余步驟跟任何編輯器都基本一致。
如果要從Illustrator中導(dǎo)出SVG,你需要選擇“File” -> “Save as”,然后從文件擴(kuò)展名下拉菜單中選擇“.svg”。一旦你選擇了.svg擴(kuò)展名,會(huì)出現(xiàn)一系列導(dǎo)出SVG的選項(xiàng)面板,比如使用哪個(gè)版本的SVG、是否在圖形中插入圖片或者在外部保存并把它們鏈入SVG、如何為SVG添加樣式(使用展示屬性或者使用CSS的style
標(biāo)簽)。
下圖展示了導(dǎo)出SVG的最佳設(shè)置:
上圖中選項(xiàng)是最佳設(shè)置的原因可以參考Micha?l Chaize的文章:使用Illustrator CC導(dǎo)出SVG。
無論你使用哪種圖形編輯器,輸出的都不會(huì)是優(yōu)化的代碼。SVG文件,尤其是從編輯器導(dǎo)出的文件,通常包含了很多多余信息,比如編輯器的meta信息、注釋、空白的組、默認(rèn)值、非優(yōu)值等,這些信息可以被安全的移除或者轉(zhuǎn)換,而不會(huì)影響SVG的生成。如果你在使用不是你自己創(chuàng)建的SVG文件,那么代碼基本上都是非優(yōu)的,所以我們推薦使用獨(dú)立的優(yōu)化工具優(yōu)化它。
這里有些優(yōu)化SVG代碼的工具。Peter Collingridge的SVG編輯器是一款在線的工具,你可以直接輸入SVG代碼,或者上傳SVG文件,然后它會(huì)提供一些優(yōu)化的選項(xiàng),如移除多余代碼、注釋、空白組、空格等等。其中有一個(gè)選項(xiàng)可以讓你指定點(diǎn)坐標(biāo)小數(shù)的位數(shù)。
Peter的優(yōu)化工具也可以自動(dòng)把inline SVG屬性移動(dòng)到文檔頭部的style
標(biāo)簽中去,這個(gè)工具最好的地方在于,當(dāng)你點(diǎn)擊某個(gè)選項(xiàng)之后,你能實(shí)時(shí)看到優(yōu)化的結(jié)果,這樣你就可以自主決定使用哪種方法優(yōu)化。某些特定優(yōu)化可能會(huì)損壞你的SVG。比如,通常一位小數(shù)應(yīng)該足夠了,但是當(dāng)你在使用一個(gè)路徑繁多的SVG文件時(shí),如果把小數(shù)的位數(shù)從四削減到一,你的文件會(huì)小掉一半,但是你的SVG也會(huì)損壞,所以能夠預(yù)覽優(yōu)化也是一個(gè)很棒的加分點(diǎn)。
Peter的工具是在線的,如果你喜歡使用離線工具,你可以嘗試SVGO(其中的“O”是“Optimizer”的縮寫),這是一個(gè)基于Node.js的工具,它有一個(gè)漂亮并簡易的拖放GUI。如果你不想要使用在線工具,它會(huì)是一個(gè)很好的選擇。
下面的截圖是用Peter的優(yōu)化工具優(yōu)化之前和之后的SVG代碼:
我們可以看到原始文件和優(yōu)化文件大小的變化,此外優(yōu)化的文件更具可讀性。
在優(yōu)化SVG之后,可以把它嵌入web頁面,之后用CSS自定義或動(dòng)畫。
HTML和CSS之間的界線很明確:HTML是內(nèi)容和結(jié)構(gòu),CSS是樣子。而SVG卻模糊了這條界線。SVG 1.1不要求使用CSS定義SVG標(biāo)簽的樣式——樣式是通過“展示屬性(presentation attribute)”應(yīng)用到SVG元素中去的。
展示屬性是在元素中設(shè)置CSS屬性的簡寫,可以把它們看成一種特殊的樣式屬性。
下面的例子是使用展示屬性為一個(gè)星形多邊形定義邊框樣式(stroke
)和背景顏色(fill
):
html <svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="300px" height="300px" viewBox="0 0 300 300"> <polygon fill = "#FF931E" stroke = "#ED1C24" stroke-width = "5" points = "279.1,160.8 195.2,193.3 174.4,280.8 117.6,211.1 27.9,218.3 76.7,142.7 42.1,59.6 129.1,82.7 197.4,24.1 202.3,114 "/> </svg>
fill
、stroke
和stroke-width
屬性都是展示屬性。
在SVG中,CSS屬性的子集可能是SVG屬性,反之亦然。SVG規(guī)范羅列了一些可能被設(shè)定為CSS屬性的SVG屬性,其中一些屬性和CSS共用,如opacity
和transform
等,其他一些不是,如fill
、stroke
和stroke-width
等。
在SVG2中,這個(gè)列表包含x
、y
、width
、height
、cx
、cy
和一些其他的展示屬性,這些屬性不能在SVG 1.1中通過CSS設(shè)置。我們可以在SVG 2規(guī)范中找到這些新屬性。
另一個(gè)設(shè)置SVG元素樣式的方法是使用CSS屬性。就像在HTML中一樣,樣式可以用inline樣式屬性設(shè)置到元素中去:
html <svg xmlns="http://www.w3.org/2000/svg" version="1.1" style="width: 300px; height: 300px;" viewBox="0 0 300 300"> <polygon style = "fill: #FF931E; stroke: #ED1C24; stroke-width: 5;" points = "279.1,160.8 195.2,193.3 174.4,280.8 117.6,211.1 27.9,218.3 76.7,142.7 42.1,59.6 129.1,82.7 197.4,24.1 202.3,114 "/> </svg>
樣式也可以使用style
標(biāo)簽定義,style
標(biāo)簽可以放在svg
標(biāo)簽中:
html <svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="300px" height="300px" viewBox="0 0 300 300"> <style type="text/css"> <![CDATA[ selector {/* styles */} ]]> </style> <g id=".."> … </g> </svg>
你也可以把它放在svg
標(biāo)簽外:
html <!DOCTYPE html><!-- HTML5 document --> <html> <head> … </head> <body> <style type="text/css"> /* style rules */ </style> <!-- xmlns is optional in an HTML5 document → <svg viewBox="0 0 300 300"> <!-- SVG content --> </svg> </body> </html>
如果你想要把svg跟標(biāo)簽完全分開,你可以使用<?xml stylesheet>
標(biāo)簽鏈入外部樣式表,代碼如下:
html <?xml version="1.0" standalone="no"?> <?xml-stylesheet type="text/css" href="style.css"?> <svg xmlns="http://www.w3.org/2000/svg" version="1.1" width=".." height=".." viewBox=".."> <!-- SVG content --> </svg>
我們之前提到展示屬性是一種特殊的樣式屬性,它們是在SVG節(jié)點(diǎn)上設(shè)置CSS屬性的簡寫,正由于此,SVG展示屬性也是樣式層級(jí)的一種。
確實(shí),展示屬性只作為低端的“作者樣式表”,它會(huì)被任何其他的樣式定義所覆蓋,如外部樣式表、文檔樣式表和inline樣式。
下面的圖表向我們展示了樣式的層級(jí),下方的樣式表會(huì)覆蓋上方的樣式表,你可以看到,展示屬性樣式會(huì)被其他所有的樣式覆蓋,除了客戶端樣式。
例如,在下面的代碼片段中描畫了一個(gè)SVG圓形元素,圓形的填充顏色是深粉色,覆蓋了展示屬性中定義的藍(lán)色:
html <circle cx="100" cy="100" r="75" fill="blue" style="fill:deepPink;" />
大多數(shù)CSS選擇器可以用來選擇SVG元素,除了一般類型的選擇器:樣式和ID選擇器之外,SVG還可以使用CSS2的動(dòng)態(tài)偽類選擇器(:hover
、:active
和:focus
)和偽元素(例如:first-child
、:visited
、:link
和:lang
)。剩下的CSS2偽元素,包括生成內(nèi)容的選擇器(例如::before
和::after
)不在SVG的定義中,因此對(duì)SVG樣式無效。
下面是一個(gè)簡單的動(dòng)畫代碼,一個(gè)深粉色的圓形,在hover的時(shí)候逐漸變成綠色:
css <style> circle { fill: deepPink; transition: fill .3s ease-out; } circle:hover { fill: #009966; } </style>
我們還可以創(chuàng)造許多更震撼的效果,Iconic有一個(gè)很簡單但是很棒的效果,當(dāng)我們hover在的燈泡上時(shí)會(huì)點(diǎn)亮燈泡,我們可以看一下這個(gè)demo。
由于展示屬性是用XML屬性表達(dá)的,所以它們對(duì)大小寫敏感,例如,當(dāng)我們要定義元素的填充顏色時(shí),屬性必須寫成fill = "..."
,而不能寫成Fill = "..."
。
此外,這些屬性的值(例如font-style = "italic"
中的italic
)也是大小寫敏感的,必須按照規(guī)范定義中的格式書寫。
其他所有以CSS屬性定義的樣式——無論是inline樣式,還是在<style>
標(biāo)簽中,或是在外部樣式表中——都是以CSS規(guī)范的語法規(guī)則定義的,通常它們對(duì)大小寫不敏感。話雖如此,SVG”樣式”規(guī)范建議我們完全按照CSS規(guī)范中定義的屬性名稱書寫,并使用同一種書寫規(guī)范(通常我們使用小寫字母和中劃線),不要利用CSS忽略大小寫的特點(diǎn)任意書寫。
SVG可以做到像HTML元素一樣,用CSS keyframe、animation屬性或者CSS transition制作動(dòng)畫。
多數(shù)情況下,復(fù)雜的動(dòng)畫效果通常包含了一些變換,有translate、rotate、scale和skewing。
在大多數(shù)情況下,SVG元素和HTML元素對(duì)于transform
和transform-origin
的解讀是一樣的,然而還是會(huì)有一些不可避免的差異。和HTML元素不同的是,SVG元素不會(huì)被盒模型所局限,因此它就不會(huì)有margin、border、padding以及content boxes。
對(duì)于HTML元素來說,transform的原點(diǎn)默認(rèn)是(50%,50%)
,也就是元素的中心。然而,SVG元素transform的原點(diǎn)默認(rèn)是用戶當(dāng)前的坐標(biāo)系統(tǒng),也就是(0, 0)
,在canvas的左上角。
假設(shè)這里有一個(gè)html元素<div>
和一個(gè)SVG元素<rect>
:
html <!DOCTYPE html> … <div style="width: 100px; height: 100px; background-color: orange"> </div> <svg style="width: 150px; height: 150px; background-color: #eee"> <rect width="100" height="100" x="25" y="25" fill="orange" /> </svg>
如果不改變它們的transform原點(diǎn),讓它們都旋轉(zhuǎn)45度,我們可以得到如圖結(jié)果(紅色的小原點(diǎn)就是它們transform原點(diǎn)所在位置):
如果想讓SVG元素在旋轉(zhuǎn)的時(shí)候繞著它自己的中心,而不是SVG canvas的左上角,應(yīng)該怎么做呢?我們需要明確地設(shè)置transform-origin
屬性來確定transform原點(diǎn)。
如何設(shè)置transform原點(diǎn)是很明確的:你設(shè)置的值與元素的border box模型相關(guān)。
在SVG中,transform原點(diǎn)的值可以是一個(gè)百分?jǐn)?shù)或者絕對(duì)的數(shù)值(比如像素)。如果transform-origin的值是百分?jǐn)?shù),那么它的位置就和元素的邊界框有關(guān)。如果它的值是一個(gè)絕對(duì)的數(shù)值,它的位置就和SVG canvas上用戶的當(dāng)前坐標(biāo)系統(tǒng)有關(guān)。
我們把<div>
和<rect>
的transform origin值設(shè)為百分?jǐn)?shù),就像這樣:
html <!DOCTYPE html> <style> div,rect { transform-origin: 50% 50%; } </style>
那么最終的變換效果是這樣的:
話雖如此,在撰寫本文的時(shí)候,F(xiàn)irefox還無法支持值為百分比的寫法。這是一個(gè)大家熟知的bug,因此最好還是使用絕對(duì)數(shù)值,我們肯定能得到所期待的效果。當(dāng)然你依然可以選擇在WebKit瀏覽器上使用百分?jǐn)?shù)值。
在接下來的例子中,我們會(huì)使用CSS animation來實(shí)現(xiàn)風(fēng)車效果。為了使風(fēng)車?yán)@著自己的中心旋轉(zhuǎn),我們會(huì)用像素和百分比來設(shè)置它的transform origin。
html <svg> <style> .wheel { transform-origin: 193px 164px; -webkit-transform-origin: 50% 50%; -webkit-animation: rotate 4s cubic-bezier(.49,.05,.32,1.04) infinite alternate; animation: rotate 4s cubic-bezier(.49,.05,.32,1.04) infinite alternate; } @-webkit-keyframes rotate { 50% { -webkit-transform: rotate(360deg); } } @keyframes rotate { 50% { transform: rotate(360deg); } } </style> <!-- SVG content --> </svg>
你可以查看Codepen上的效果。這里要注意的是,在撰寫此文的時(shí)候,SVG元素上的CSS 3D transformation還不能使用硬件加速,所以3D的效果跟2D完全一樣,然而,F(xiàn)irefox已經(jīng)能夠一定程度上提升transform的速度。
現(xiàn)在還無法用CSS animation將SVG路徑從一個(gè)形狀改變成另外一個(gè)形狀。如果你想要改變路徑,也就是從一個(gè)動(dòng)畫過渡到另一個(gè)路徑,必須要用到JavaScript。如果你想要實(shí)現(xiàn)這樣的效果,我建議你使用Dmitry Baranovskiy寫的Snap.svg,他還寫了SVG LibraryRapha?l。
Snap.svg相對(duì)于SVG的地位就好像jQuery相對(duì)HTML的地位一樣,它能讓我們更簡單的處理SVG的一些特殊情況。
雖然不能用CSS改變形狀,但是你卻可以用CSS來創(chuàng)建一個(gè)動(dòng)態(tài)的畫線效果。使用animation的時(shí)候,你必須要先設(shè)定線條路徑的總長度,然后用SVG的stroke-dashoffset
和stroke-dasharray
屬性實(shí)現(xiàn)畫畫效果。一旦你知道路徑長度,就可以通過下面的方法來實(shí)現(xiàn)動(dòng)畫了:
css #path { stroke-dasharray: pathLength; stroke-dashoffset: pathLength; /* transition stroke-dashoffset */ transition: stroke-dashoffset 2s linear; } svg:hover #path { stroke-dashoffset: 0; }
在上面的例子中,當(dāng)hover SVG時(shí),圖形路徑會(huì)在2秒內(nèi)畫好。
在接下來的演示中,我們將會(huì)用到同樣的原理,再加上CSS的transition延遲,讓燈泡在路徑動(dòng)畫完成時(shí)點(diǎn)亮。
css #cable { stroke: #FFF2B1; stroke-dasharray: 4000 4000; stroke-dashoffset: 4000; stroke-width: 4; transition: stroke-dashoffset 8s linear; } svg:hover #cable { stroke-dashoffset: 0; } /* turn lamp on */ .inner-lamp{ fill:grey; transition: fill .5s ease-in 6s; } svg:hover .inner-lamp { fill: #FBFFF8; } /* … */
你可以在JS Bin中查看demo,提醒大家,你同樣可以寫成stroke-dasharray: 4000
而不是stroke-dasharray: 4000 4000
——如果兩個(gè)值相同,你可以只定義一個(gè)值。
有時(shí)候,可能你并不能知道動(dòng)畫路徑的確切長度,這時(shí),你可以用到JavaScript的getTotalLength()
方法來獲取。
js var path = document.querySelector('.drawing-path'); path.getTotalLength(); //set CSS properties up path.style.strokeDasharray = length; path.style.strokeDashoffset = length; //set transition up path.style.transition = 'stroke-dashoffset 2s ease-in-out'; // animate path.style.strokeDashoffset = '0';
上面這個(gè)片段是一個(gè)非常簡單的例子,它用JavaScript實(shí)現(xiàn)了我們之前用CSS達(dá)到的效果。
Jake Archibald針對(duì)此技術(shù)寫了一篇詳細(xì)的文章。Jake在文章里寫了一個(gè)很棒的交互演示,展現(xiàn)了動(dòng)畫到底是如何實(shí)現(xiàn)的,以及這兩個(gè)SVG屬性如何共同實(shí)現(xiàn)我們想要的效果。如果你對(duì)這個(gè)技術(shù)感興趣,我建議你讀一下他的文章。
一個(gè)SVG文件可以通過六種方法嵌入到文檔中,每一種都有各自的優(yōu)點(diǎn)和缺點(diǎn)。
我們討論嵌入技術(shù)的原因是,你嵌入SVG的方法會(huì)影響到一些CSS樣式、動(dòng)畫、交互是否會(huì)實(shí)現(xiàn)。
以下為SVG的嵌入方法:
<img>
標(biāo)簽嵌入: <img src="mySVG.svg" alt="" />
.el {background-image: url(mySVG.svg);}
<object>
標(biāo)簽嵌入: <object type="image/svg+xml" data="mySVG.svg"><!-- fallback here --></object>
<iframe>
標(biāo)簽嵌入: <iframe src="mySVG.svg"><!-- fallback here →</iframe>
<embed>
標(biāo)簽嵌入: <embed type="image/svg+xml" src="mySVG.svg" />
<svg>
標(biāo)簽嵌入: <svg version="1.1" xmlns="http://www.w3.org/2000/svg" …>
<!-- svg content →
</svg>
從引入外部SVG文件現(xiàn)在大部分都使用<object>
標(biāo)簽,這個(gè)標(biāo)簽最大的好處是在SVG沒有渲染的時(shí)候能夠優(yōu)雅降級(jí),提供圖片(或者文本)。當(dāng)SVG因?yàn)槟承┰驔]有加載時(shí)——比如提供的URI錯(cuò)誤——瀏覽器就會(huì)展現(xiàn)<object>
起始標(biāo)簽和結(jié)束標(biāo)簽里面的內(nèi)容。
html <object type="image/svg+xml" data="mySVG.svg"> <img src="fallback-image.png" alt="…" /> </object>
如果你想實(shí)現(xiàn)高級(jí)的SVG特效,比如CSS或者scripting,HTML5的<object>
標(biāo)簽就是你最好的選擇。
因?yàn)闉g覽器在用它們各自的方式渲染SVG文檔,所以可以用iframe來完成嵌入和展現(xiàn)SVG。如果你想要完全將SVG代碼和腳本在主頁面中分離,這會(huì)是一個(gè)很好的方法。然而,用JavaScript控制SVG圖片有點(diǎn)困難,并且同時(shí)還會(huì)受到同源策略的限制。
<iframe>
標(biāo)簽就像<object>
一樣,當(dāng)瀏覽器不支持SVG或者因?yàn)槟承┰驘o法渲染的時(shí)候會(huì)提供回退機(jī)制。
html <iframe src="mySVG.svg"> <img src="fallback-image.png" alt="…" /> </iframe>
<embed>
標(biāo)簽不是HTML規(guī)范的一部分,卻仍然得到了廣泛的支持,它用來囊括需要外部插件才能工作的內(nèi)容。Adobe公司的Flash插件就需要用到<embed>
標(biāo)簽,支持這個(gè)標(biāo)簽為唯一原因是為了使用SVG,<embed>
標(biāo)簽沒有默認(rèn)回退機(jī)制。
SVG也能使用<svg>
標(biāo)簽inline嵌入到文檔中——作為一個(gè)”代碼塊”,這是當(dāng)下嵌入SVG最主流的方法之一。使用inline的SVG和CSS會(huì)比較容易,因?yàn)闊o論樣式規(guī)則放置在頁面的哪個(gè)位置都可以輕松定義SVG的樣式和動(dòng)畫。也就是說,樣式不需要包含在<svg>
標(biāo)簽里,這對(duì)于其他技術(shù)來說這也是很必要的。
inline嵌入SVG是一個(gè)很好的選擇,只要你愿意增加頁面的尺寸,并且放棄它向下兼容性(因?yàn)樗鼪]有默認(rèn)回退機(jī)制)。要注意的是,inline嵌入SVG不能緩存。
在定義CSS樣式和動(dòng)畫的時(shí)候,用<img>
標(biāo)簽和作為CSS背景圖片嵌入SVG很類似。一旦嵌入了SVG,外鏈的CSS資源中的樣式和動(dòng)畫不會(huì)被保留。
下面的表格展現(xiàn)了用六個(gè)不同的方法嵌入SVG時(shí),CSS動(dòng)畫和交互(比如hover效果)是否會(huì)被保留。最后一列是將它與SMIL animations比較,無論哪種情況, SVG animations (SMIL) 都支持。
CSS交互 (例如:hover) | CSS動(dòng)畫 | SVG動(dòng)畫 (SMIL) | |
---|---|---|---|
<img> | 否 | 是 只在<svg> 中 | 是 |
CSS背景圖片 | 否 | 是 只在<svg> 中 | 是 |
<object> | 是 只在<svg> 中 | 是 只在<svg> 中 | 是 |
<iframe> | 是 只在<svg> 中 | 是 只在<svg> 中 | 是 |
<embed> | 是 只在<svg> 中 | 是 只在<svg> 中 | 是 |
<svg> (inline) | 是 | 是 | 是 |
表格展示了當(dāng)SVG嵌入時(shí),CSS樣式、動(dòng)畫和交互是否會(huì)被保留
以上表格中都是標(biāo)準(zhǔn)行為的,然而,在每個(gè)瀏覽器中實(shí)現(xiàn)效果可能有差異,也可能存在bug。
這里要注意的是,即使SMIL animations會(huì)被保留,但在SVG被當(dāng)做圖片嵌入的時(shí)候(比如<img>
或者CSS背景圖片),SMIL的交互效果也是沒有的。
在嵌入SVG之后,你需要保證它是響應(yīng)的。
根據(jù)你選擇的嵌入技術(shù),你需要應(yīng)用一些特定的hack使得你的SVG是跨瀏覽器響應(yīng)的,這是由于每個(gè)瀏覽器判定SVG的尺寸都不同,每個(gè)瀏覽器中SVG的實(shí)施方法也不同。因此,SVG的操作方法不盡相同,我們需要調(diào)整一些樣式讓SVG一直能跨瀏覽器響應(yīng)。
我不會(huì)過多贅述瀏覽器矛盾,我只會(huì)簡單介紹一下讓SVG響應(yīng)式所需的調(diào)整和hack。如果你想要了解瀏覽器矛盾和bug,可以看一下我在Codrops上的文章。
無論你選擇什么技術(shù),第一步要做的事情就是從<svg>
元素中刪除height
和width
屬性。
你需要保留viewBox
屬性,并把preserveAspectRatio
屬性設(shè)為xMidYMid meet
,記住如果preserveAspectRatio
的值已經(jīng)默認(rèn)為xMidYMid meet
的話就不需要特意設(shè)置了。
當(dāng)SVG作為CSS的背景圖片嵌入時(shí),不需要額外的調(diào)整或者h(yuǎn)ack,SVG會(huì)表現(xiàn)的和其他位圖背景圖片一模一樣。
在所有瀏覽器中,如果SVG是通過<img>
標(biāo)簽嵌入的話,SVG會(huì)自動(dòng)拉伸到容器寬度(當(dāng)然是在刪除<svg>
標(biāo)簽上的寬度值之后),然后它會(huì)按照預(yù)期伸縮,在除了IE之外的所有瀏覽器中自適應(yīng)。IE會(huì)把SVG的高度設(shè)為150像素妨礙正確的伸縮。為了解決這個(gè)問題,你需要把<img>
的寬度設(shè)為100%。
html <img src="mySVG.svg" alt="SVG Description." /> img { width: 100%; }
這同樣也適用于<object>
標(biāo)簽嵌入,出于同樣的原因考慮,你也需要設(shè)置<object>
標(biāo)簽的寬度為100%:
css object { width: 100%; }
即使<iframe>
跟<object>
有很多相同之處,瀏覽器也會(huì)分別對(duì)待。所有瀏覽器會(huì)默認(rèn)設(shè)置CSS中替換元素的尺寸為300*150像素。
保持SVG寬高比同時(shí)讓iframe響應(yīng)式的唯一方法,是使用由A List Apart的Thierry Koblentz首創(chuàng)的“padding hack”。padding hack的思路是利用元素padding和寬度的關(guān)系,來創(chuàng)建一個(gè)寬高比固定的元素。
當(dāng)一個(gè)元素的padding值設(shè)為百分比,這個(gè)百分比會(huì)根據(jù)元素的寬度來計(jì)算,即使你設(shè)置的是元素的padding-top
或padding-bottom
。
為了應(yīng)用padding hack并使SVG響應(yīng)化,SVG需要被裝在一個(gè)容器中,然后你需要在容器和SVG(例如iframe)中添加樣式。
html <!-- wrap svg in a container --> <div class="container"> <iframe src="my_SVG_file.svg"> <!-- fallback here --> </iframe> </div> .container { /* collapse the container's height */ height: 0; /* specify any width you want (a percentage value, basically) */ width: width-value; /* apply padding using the following formula */ /* this formula makes sure the aspect ratio of the container equals that of the SVG graphic */ padding-top: (svg-height / svg-width) * width-value; position: relative; /* create positioning context for SVG */ }
svg-height
和svg-width
變量分別是<svg>
的高度和寬度值——就是我們之前刪除的尺寸。width-value
是你想要設(shè)置的任何SVG容器寬度。
最后,SVG自身(iframe)需要在容器中絕對(duì)定位:
css iframe { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
我們把iframe絕對(duì)定位的原因是合并容器的高度再加上padding會(huì)導(dǎo)致iframe超出容器邊界。所以,“為了把它拉回來”,我們把它絕對(duì)定位。欲知詳情,請(qǐng)看我Codrops上的文章。
最后,當(dāng)我們把高度和寬度刪除之后,<svg>
標(biāo)簽里的SVG會(huì)響應(yīng)化,因?yàn)闉g覽器會(huì)假定一個(gè)100%的寬度,使得SVG按照這個(gè)寬度伸縮。然后,IE會(huì)像我們之前提到的<img>
標(biāo)簽一樣,有一個(gè)150像素的固定高度。不幸的是,把SVG的高度設(shè)為100%對(duì)這個(gè)bug無用。
為了讓SVG在IE中自適應(yīng),我們也需要添加padding hack。所以,我們?cè)?code style="font-family: monospace, monospace; font-size: 1em;"><svg>標(biāo)簽外套一個(gè)容器,在容器中添加padding hack,最后讓<svg>
絕對(duì)定位,這里唯一的不同是,我們不需要設(shè)定<svg>
的寬高。
css svg { position: absolute; top: 0; left: 0; }
SVG也會(huì)接受并相應(yīng)CSS媒體查詢。你可以使用媒體查詢來告便SVG在不同viewport下的樣式。
然后這里有個(gè)很重要的注意事項(xiàng),SVG相應(yīng)地viewport是SVG本身的viewport,不是頁面的viewport!
這跟元素查詢的概念很像。
當(dāng)SVG插入<img>
、<object>
和<iframe>
中時(shí),它響應(yīng)的是這些元素建立起來的viewport。也就是說,這些元素的尺寸會(huì)生成描繪SVG的viewport,也會(huì)生成CSS媒體查詢條件應(yīng)用的viewport。
下面這個(gè)例子展示了包含媒體查詢的SVG,SVG指定為<img>
標(biāo)簽:
html <svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 194 186"> <style> @media all and (max-width: 50em) { /* select SVG elements and style them */ } @media all and (max-width: 30em) { /* styles */ } </style> <!-- SVG elements here --> </svg>
當(dāng)<img>
的max-width
是50em
或者30em
時(shí),SVG會(huì)應(yīng)用媒體查詢中的樣式。
html <img src="my-logo.svg" alt="Page Logo." />
如果你想了解更多SVG中的媒體查詢,你可以看一下Dev.Opera中Andreas Bovens的文章。
SVG是圖片,就像圖片有可訪問性一樣,SVG也有,你需要保證你的SVG具有可訪問性。
我還是要再強(qiáng)調(diào)一遍:讓你的SVG具有可訪問性,你有很多種方法實(shí)現(xiàn),如果你想要一個(gè)全面的概覽,我推薦SitePoint上Leonie Watson的文章,她提出一些很好的方法,比如在<svg>
中使用<title>
和<desc>
標(biāo)簽、使用ARIA屬性等。
除了可訪問性,不要忘記優(yōu)化你的SVG,為不支持的瀏覽器提供回退。我推薦Todd Parker的演講。
最后,你可以在caniuse上查看不同SVG特性的支持情況。我希望你覺得我這篇文章對(duì)你有用的,感謝你的閱讀。
聯(lián)系客服