1. 程式人生 > >深入淺出CSS3:background-clip,background-origin和border-image教程

深入淺出CSS3:background-clip,background-origin和border-image教程

已相容IE!之前不能相容IE,給您的閱讀帶來不便十分抱歉,Sorry

一.這篇部落格的初衷

  最近在準備一個下學期參加比賽的概念網站,希望能用到CSS3的新特性,比如background的background-clip或background-origin或border-image。但僅僅是依靠w3schools上的文件和說明發現很多臆想中的效果都實現不了。於是嘗試在百度中搜素,結果資料也是少的可憐,反覆轉載的只有一篇來自懌飛部落格的background-clip與background-origin 的一則運用

,但畢竟是幾年前的文章,其中的部分內容已經不適用於現在的標準了,其他的搜尋結果也不是很理想於是乎只好自己動手豐衣足食。花了一至了兩天把這個內容消化。同時把要點和精總結在這篇部落格中,給自己和大家做一個參考。

二.從傳統的多影象背景技術談起

在CSS3之前,2.0也好,2.1也罷。要想給一個塊級元素新增圓角或是陰影,又或是一個比較複雜的背景影象(比如多邊形,多紋路)都是相當困難的一件事。在這裡先列舉兩個例子,有關如何組織複雜的背景和陰影效果。一方面是為了照顧一些入門web的朋友,另一方面也為了和後面這兩個技術的應用做一個對比,做一個承上啟下的作用。熟練的朋友可以跳過這一節,直接從下一節開始閱讀

  1.請大家先看這樣一個效果:注意文字的背景,大家有沒有主意如何實現?一個最普通不過的想法是,我就按我需要的文字的長度,用photoshop做一個包含左右半圓形狀的完整一體圖片。但問題是,如果我文字的長度需要更改,變得更長或者更短時應該怎麼辦?為了不影響美觀,我們又不得不把圖片放回photoshop中返工?雖然不排除這是一種辦法。但要是有非常多的頁面和框背景需要用到這個圖片,那工作量會是非常巨大的。很明顯這是得不償失的。於是我們會想,手動的讓圖片適應文字麻煩,要是能讓圖片自動能適應文字,是絕對的事半功倍。那究竟有沒有這樣一種方法呢?

  答案是肯定的(在這裡我們簡略的談一下關鍵思路,具體程式碼的實現就不深究了),為了實現這個效果,通常我們只需要三幅圖:。具體原理如所示:

  相信看到圖之後有朋友應該有不少已經心領神會了:我們在原來唯一一個用來存放文字的div中,又插入了三個div:div#left,div#center,div#right。其中#left和#right分別用來存放半圓形的左右邊緣且固定寬度,而中間的#center用來存放文字,背景採用repeat-x定位,且不定位寬度,再通過其它css設定讓它能收縮緊貼內容區域(content),這樣就能隨著文字的長短而自如伸縮了。最後通過position或display屬性讓#lef,#center,#right實現無縫隙的拼接,同時讓最外層的div#content也收縮緊貼它包裹的三個div,然後——大功告成。

這個技術的關鍵在於如何讓存放文字的div#center的伸縮引起外部整個div#content的的伸縮,且保持#left,#center和#right的佈局不被破壞(要無縫才能讓人感覺一體,感覺真是)……當然這不屬於我們今天的討論範圍,有興趣的朋友可以參考我之前的一篇《深入理解css盒子模型》。這樣就完成了自動伸縮功能。精簡的程式碼如下:

<div class=”content” style=”height:32px;”> /*這個是伸縮的*/ <div class=”left” style”width:15px; height:32px;”></div><div class=”center” style=”height:32px;”>這裡存放文字內容</div>/*這個也是可以伸縮的*/ <div class=”right” style=”width:15px; height:32px;”></div></div>

   但至於如何才能使最外層的容器內收縮緊貼內部div,使div#center自動伸縮,就不在本課的範圍之內,大家可以百度,也可以參照我上一篇文字《深入理解box盒子模型》。

例子2.我們先看一個jQuery外掛fancybox的陰影效果:

這是模仿MacOS的效果的一個外掛,由於整張圖片太大,我只是截取了一個角下來。大家需要注意的重點是白色邊框的外邊緣的陰影效果(可能不是很明顯)——參照上面的例子,您覺得陰影效果是如何實現的?

  對,還是用九個盒子拼成的(可能這裡有朋友會想到滑動門技術,的確這也是實現陰影的方法之一,但為了承上,這裡暫且不介紹),一個盒子裝的是中間的照片,另外八個盒子分別裝東,西,南,北,東南,西南,東北,西八個方向的陰影。這個不用畫圖,大家應該可以想象出來吧。但這個例子又有不同——這一次有九個盒子,要是按上一個例子一樣,在一容中放九個盒子,再通過浮動,定位屬性等來實現他們無縫拼接,也會是相當繁瑣的一事。因為要考慮每一個盒子周圍的盒子在自己伸縮時也能適當的做一些調整,不至於出現錯位和縫隙。所以的這次的做法是將放陰影的八個盒子用絕對定位固定在中間的盒子的八個方向上,這樣以中心盒子為中心,無論它怎麼放大還是縮小,周圍八個盒子都死死的附屬著它,就再也不用考慮自己周圍的盒子有錯位之類的問題。圖例如下:

再看看實際的定位是不是這樣定位的呢,看看從firebug下的截圖:


再看看其中一個fancybox-bg-n的具體css:

,background-clip,background-origin入門

我想說的是,上面的兩個例子總結起來只有兩個字:麻煩。背景明明只關一個div的事,結果硬是要n多個不相關的div來輔助完成效果——background-clip,backgrou nd-origin便是我們的救星。要知道CSS3的任何新屬性不是W3C人吃飽了撐的沒事找事想出來來的,它的出現必然性必定是經過詳細驗證的且有它必要的價值。相信當您閱讀完這一節的內容後,你就會開始學會如何用新技術擺脫那些陳舊繁瑣的步有三個屬性來就不復雜的效果了。

在開始之前,先做幾點說明,請看:


  首先我們要引入幾個概念(呃,這是我自己翻譯的,不知道對不對,可能孤陋寡聞了,請朋友們見諒):內容邊緣(content edge),內邊距邊緣(padding edge),邊框邊緣(border edge),外邊距邊緣(margin edge)。為了理解,我們可以把內邊距,邊框,外邊距看成一個環形的容器,並且每個環形容器都只有兩條邊,一條衝內,一條衝外(內和外也是相對的,好比外邊距的外邊就是邊框的內邊),於是我們把衝外(outer)的那條邊稱為這個環形的邊緣(edge)。當然因為內容區域是“實心”的,所以不存在內外的問題。  

  origin的翻譯過來時原始的意思。顧名思義,所以background-origin是用來決定圖片的原始起始位置。它有三個可選值content-box,padding-box,border-box(background-origin如果寫在css中只有Opera瀏覽器可以識別,如果希望在火狐或者chrome或Safari中使用,要使用它們瀏覽器的私有屬性-moz-background-origin(Firefox),-webkit-background-origin(chrome,safari),並且對應的值是content,padding,border,省略了-box),即你可以選擇背景圖片是從內容區域開始顯示,還是內邊距,還是邊框。

  舉個例子,我們有一個div,關鍵在定位它的背景圖片,為了讓演示的效果更明顯,我們讓它從左上角開始定位,position:left top並且no-repeat。並且內容區於圖片大小一致,邊框和內邊距都設定為30畫素寬。OK,

在沒有加入background-origin之前的程式碼為:

複製程式碼 .border { background:url("images/qwqw_s.jpg"); background-repeat:no-repeat; background-position:left top; border-width:30px; border-style:dashed; border-color:red; width:180px; height:254px; padding:30px; margin:0 auto;} 複製程式碼

設定background-origin之後的效果圖:

  因為是在火狐下做的測試,所以-moz-background-origin代替background-origin,相應的屬性所以也去掉了-box  

  效果和作用已經一目瞭然了:我們看到,當background-origin的值為content-box時,首先會讓背景圖片的左上角和內容邊緣左上角對齊,padding-box時,則會讓背景圖片的左上角和內邊距的左上角對齊。以此類推。可見background-origin的值的確是決定背景圖片開始從哪個區域開始顯示。但話說回來,如果我沒有設定任何的background-origin屬性的話,它預設的起始位置在哪呢?這裡就不演示了,但有必要記住——padding。

  有一點要十分的注意:如果背景不是no-repeat的話,這個屬性是無效的。它會從border-box區域開始顯示,這一點很重要。

  background-origin屬性就先介紹到這裡。應該不難吧。下面繼續介紹background-clip。之所以沒有把這兩個屬性分為兩節分別介紹,因為實戰的經驗告訴我這兩個屬性應該是相互搭配才能相得益彰。

  clip原意為裁剪,擷取。同樣顧名思義,background-origin的作用為將背景圖片做適當的裁剪,以適應需要。當然這裡並不是真正意義上的把圖片給裁剪了,而是根據屬性值。把圖片的某些部位做適當的隱蔽。background-clip與origin的可選擇一樣,也是有content-box,padding-box,border-box(要注意在火狐和Chrome和Safari中,需要使用私有屬性,加上-mox-和-webkit-,這裡就不贅述了,參考解釋background-clip的內容)。怎樣個剪裁法呢。根據你設定的盒子部位,那麼圖片在這個部位的外邊緣以外的部分都會不可見。舉個具體例子,圖片起始位置和上面的例子一樣,比如是從border-box開始,但我background-clip設定的值是content-box,在content之外,也就是border-box內,padding-box內的圖片內容統統不可見。儘管你是讓圖片從邊框開始顯示。例項如下

複製程式碼 .border { background:url("images/qwqw_s.jpg") black; background-repeat:no-repeat; background-position:left top; border-width:30px; border-style:dashed; border-color:red; background-clip: content-box; background-origin: border-box; -moz-background-clip: content; -moz-background-origin: border; -webkit-background-clip: content; -webkit-background-origin: border; width:180px; height:254px; padding:30px; margin:0 auto;} 複製程式碼

  正如以上所說,我們可以看見雖然圖片是從頂著邊框的左上角進行定位,但是裁剪屬性background-clip的屬性是設定為content-box,所以只有content區域的內容看得見,也就是隻要是在content之外的圖片內容都被隱蔽掉了。

  我之所以要在不同瀏覽器下進行測試(Firefox/3.6.3,Google:7.0.517.24,Opera/9.80,Safari:5.0.1),答案也在圖上,我們看到在火狐下的結果和其他瀏覽器結果竟然不一樣。明明background-clip設定的屬性是content-box,但卻沒有圖片的任何部位被遮蔽。我想說的是:在火狐下-moz-background-clip屬性是沒有content這一值的(但是padding和border還是有的),在firebug中可以看到,-moz-background-clip的值直接是border,當你強行改為content時,這條屬性會直接從bug中消失。當然這只是在3.6.3版本下的結果,至於在4.0版本中表現如何(雖然只是beta版)。可以自行測試

四.實戰

在學習了基本background-clip和background-origin用法和原理之後,我們將通過操作一個實際的例子,來加深我們的學習:

                  

這個圓角背景是由三部分組成:(呃,其實是從Webqq2.0網站上撬下來的,就是上面的工具條……但是作為教學用,應該無傷大雅吧……),思路和開篇的那個黑背景製作過程是一樣的,左右固定,中間窄的repeat-x。但是這會不用插入三個div,又要設定float,又要設定display考慮佈局那麼麻煩。

步驟一:

先搭建一個框架出來,給一個佈局。不著急把圖片插入進去。主意看以下程式碼,有幾點需要說明的:因為僅需在盒子左右兩側插入背景,且恰好為左右要插入圖片的寬度(如果不恰好為那麼寬呢?那麼不會成功的,因為css3中還沒有屬效能控制圖片在邊框中的定位,你會想不是有background-position屬性嗎?要注意那個是控制圖片在整個盒子中的定位。還是不信的話你可以親自試試);還有就是padding的值也是可以不用設定的,是為了與上面的例子盡力保持一致,方便大家對比學習 margin也是為了讓盒子居中而已,可以忽略;最後border-style和border-color也是方便大家理解佈局才新增上去的。

複製程式碼 .border { background:black; border-width:0 11px;/*為了要適應左右兩個圖片的寬度,且只有左右需要,上下的寬度就不需要了*/ border-style:dashed; border-color:Red; width:180px; height:90px;/*因為要適應圖片,所以寬度改小一點*/ padding:30px;/*其實Padding也是可以不需要的,為了方便說明一些問題,還是保留*/ margin:0 auto;} 複製程式碼

步驟二:

這一步很簡單,就是把中間需要x軸重複的圖片新增上去,並且把黑色背景去掉

複製程式碼 .border { background:url("images/tool-bar/bg_b_c.png");/*新增背景*/ background-repeat:repeat-x; background-position:center; border-width:0 11px;/*為了要適應左右兩個圖片的寬度,且只有左右需要,上下的寬度就不需要了*/ border-style:dashed; border-color:Red; width:180px; height:90px;/*因為要適應圖片,所以寬度改小一點*/ padding:30px;/*其實Padding也是可以不需要的,為了方便說明一些問題,還是保留*/ margin:0 auto;} 複製程式碼

步驟三:

這步也很簡單,就是把中間重複的背景的左右兩端去掉,為了方便我們下一步在左右邊框中插入需要的圖片。注意這裡的

 -moz-background-origin的content屬性是無效的,實際上這裡的值是padding。正如在上一節的最後說道,在火狐中是沒有content這個屬性的。如果有朋友想要copy這段程式碼,記得根據瀏覽器版本做相應的修改,把origin的值content改為padding,或者把盒子的padding去掉。

複製程式碼 .border { background:url("images/tool-bar/bg_b_c.png"); background-repeat:repeat-x; background-position:center; -moz-background-clip: padding; -moz-background-origin: content;/*firefox中background-origin沒有content這個屬性,其實現在的值是padding。在其他瀏覽器中是有效的*/ border-width:0 11px;/*為了要適應左右兩個圖片的寬度,且只有左右需要,上下的寬度就不需要了*/ border-style:dashed; border-color:Red; width:180px; height:90px;/*因為要適應圖片,所以寬度改小一點*/ padding:30px;/*其實Padding也是可以不需要的,為了方便說明一些問題,還是保留*/ margin:0 auto;} 複製程式碼

步驟四:

這一步還是很簡單,插入邊框的左右兩張圖片,並設定好position,repeat,clip等值。注意當存在多個圖片時,設定值的格式,用逗號隔開。

複製程式碼 .border { background:url("images/tool-bar/bg_b_c.png"),               url("images/tool-bar/bg_b_l.png"),               url("images/tool-bar/bg_b_r.png"); background-repeat:repeat-x,no-repeat,no-repeat; background-position:center,left center, right center; -moz-background-clip: padding,border,border; -moz-background-origin: content,border,border; border-width:0 11px;/*為了要適應左右兩個圖片的寬度,且只有左右需要,上下的寬度就不需要了*/ border-style:dashed; border-color:Red; width:180px; height:90px;/*因為要適應圖片,所以寬度改小一點*/ padding:30px;/*其實Padding也是可以不需要的,為了方便說明一些問題,還是保留*/ margin:0 auto;} 複製程式碼

重要提示!寫到這一步,可以從上圖看到已經快大功告成了。把左右的紅色邊框去掉就可以了——那麼把border-color改為none或是直接去掉這句話?不行的。如果不設定顏色的話邊框就會變成黑色,因為邊框有樣式,而且樣式還有11px寬啊,所以會用預設的黑色來填充。現在你可能又會覺得是邊框樣式border-style的問題,那咱們把樣式去掉,把寬度保留?也不行,因為如果沒有樣式寬度是無效的,結果會如下圖(我們可以從firebug中看到邊框的寬度是0,雖然仍然保留border-width)。所以border-style,border-color,border-width缺一不可!這一點要十分注意!

步驟五:

綜上所述,你可能會覺得既不能改border-style又不能改border-color豈不是沒轍了?正確答案是——還是修改border-color,別忘了,color還有一個值transparent,透明。顏色還讓它在,但只要人們看不見就行了。我們實現它:

複製程式碼 .button { background:url("images/Fancybox/fancy_title_main.png"),               url("images/Fancybox/fancy_title_left.png"),               url("images/Fancybox/fancy_title_right.png"); background-repeat:repeat-x,no-repeat,no-repeat; background-position:center,left,right; background-clip: padding-box,border-box,border-box; background-origin:padding-box,border-box,border-box; -moz-background-clip: padding,border,border; -moz-background-origin: content,border,border; border-width:0 15px; border-style:dashed; border-color:transparent; width:80px; height:32px;} 複製程式碼


OK,徹底大功告成,很簡單不是嗎。

 四.border-image

寫到這裡我發現文章的戰線貌似拉的有點長了。所以我打算border-image在這裡只是作為附加內容說明,並不會深究,儘可能簡扼一些。開始(所以廢話也簡扼一些……):

  border-image是定位在邊框上的圖片——那不是和把background-origin屬性設為border差不多一個意思?是的,的確有這層含義。但在接下來的說明和例子中,你將看到它的便利之處。

  這個屬性說到底還是在搗鼓一張圖片。先直接看一張說明圖片:

      

  草圖左邊是舉例border-image所使用的圖片,右邊的草圖是比喻一個盒子。border-image有兩個值需要設定,頭一個是切割屬性(border-image-slice),最多有四個值可以設定,命名規則和margin、padding都是一致的,順序上右下左。四個值對應左邊草圖的不同區域的寬度,同樣上右下左的順序,也就是2,6,8,4區域的寬度(4、6區域為橫向長度,2,8區域為叢向長度)。從圖中可知,因為是交集的緣故,只要定義好這四塊的寬度,1、3、9、7區域的長寬也就隨之確定。在對映到盒子模型上,從1到9(除5)正好連成盒子的邊框區域,這樣盒子的邊框圖片就有著落了。

  但還有一個疑問。如果實際圖片真如左邊草圖那麼小,而實際盒子真有右邊草圖的那麼大,那2、6、8、4區域的圖片可能就不夠用呀?問得好,所以border-image還提供一種機制來處理這個問題——圖片重複屬性(border-image-repeat),也叫拉伸值(stretch value)。有四個值可以選擇:stretch(拉伸且預設)、repeat(重複)、round(平鋪)。是不是聽著很耳熟,對,和電腦桌布的位置屬性是一樣的。對每一張border-image最多可以設定兩個拉伸屬性如round round。前一個針對圖片側邊(除5區域以外),後一個針對中間部分,即5區域。如果只有一個值的話,則認為所以區域都按照此值佈置。若無設定此屬性,則按預設值拉伸(stretch)來佈置image。

所以對應上圖,咱們再來一個例子,就一目瞭然了:

  回到上節的那個例子,這回我們只需要兩張圖片:

  可以看出後面那種圖就是左右兩側拼接而成的,這回咱們用border-image屬性完成上面的同樣效果,很簡單,直接看CSS程式碼:

複製程式碼 .border { background:url("images/tool-bar/bg_b_c.png"); background-repeat:repeat-x; background-position:center; -moz-background-clip: padding; -moz-background-origin: padding; -moz-border-image:url("images/bg_b_l_r.png") 0 11; border-width:0 11px;/*為了要適應左右兩個圖片的寬度,且只有左右需要,上下的寬度就不需要了*/ width:180px; height:90px;/*因為要適應圖片,所以寬度改小一點*/ padding:0 30px;/*其實Padding也是可以不需要的,為了方便說明一些問題,還是保留*/ margin:0 auto;} 複製程式碼

還是要做幾點說明。因為在這個例子中我們只需要左右側有圖片,所以切割屬性只要將圖片左右切割開去可以了:0 11。在上一節最後一步的重要提示中,我反覆強調border-style,border-color,border-width缺一不可。但在這裡只需要一個border-width就足夠了!這就是它的便利之處。但在使用時要記得不同瀏覽器之間的差異,判斷是否要使用-moz-或-webkit-或-o-字首。

再給大家看幾個驚豔的例子:

----->

還有小的:------->

至於具體CSS程式碼嘛,其實很簡單,這裡就給大家賣個關子吧。當做思考題咯

 五.再嘮叨幾句

如果大家在閱讀過程中有什麼疑惑,或發現什麼錯誤,甚者是錯別字,都可以留言給我。我將盡快給大家回覆,修正。很樂意與大家交流。

一直覺得部落格園永遠是.net,c#,MVC之類的後臺天下。有關web前端的文章不少,但含金量遠遠不如那些多。雖然我學的是.net方向,但前端始終是摯愛。因為部落格園這裡前端的資料的匱乏。所以自己一旦遇到了很多前端的問題都只能google國外的文章,或是去stack overflow(但真的很有效果,回覆的速度快,集思廣益,而且句句錙銖。不像國內全都是“頂”啊,“標記”之類的廢話,向大家強烈推薦)。

  前端的冷落是不是真的因為前端是開源,比如html程式碼,只要把想要網站的圖片和樣式copy一下改一改就是了。毫無技術可言?還是JavaScript和jQuery這種東西和C#、Java比起來真的簡單很多 ?呵,希望有興趣的朋友能和我留言交流交流。

  歡迎轉載,轉載請註明出處