淘寶的新Sprite方法——使用Img Sprite技術對按鈕加載順序優化的簡單研究

導言

話說web前端的技術先驅,國外當屬Yahoo,而國內則當屬淘寶。因此它們的一舉一動都是整個互聯網的風向標。css

就在前幾天,偶然發現曾經一直困擾本身的鼠標懸停共用部分空間的問題在淘寶這裏有瞭解決方案,立刻拿來分析下。html

懸停狀態共用某一區域

用語言描述老是怪怪的,仍是上圖吧。前端

001

能夠看到,按照正常的的導航製做方法,每一個按鈕元素都有本身的獨立區域,它們之間互不影響。但在本例中,兩個按鈕卻在懸停狀態下共用了中間一條線的區域,它是如何實現的,咱們一步步來分析。先看它的背景原圖(其它部分不重要,無視之)web

sprites

從原圖上看,與咱們傳統的Sprite並沒有區別。再來看看Html結構瀏覽器

?
1
2
3
4
5
6
/*這是我本身寫的,與淘寶原始結構稍有不一樣*/
< ul >
     < li class = "nav1" >< a href = "#" >1</ a ></ li >
     < li class = "nav2" >< a href = "#" >2</ a ></ li >
     < li class = "nav3" >< a href = "#" >3</ a ></ li >
</ ul >

此結構與正常結構並沒有區別,繼續用普通方法定義CSS性能優化

?
1
2
3
4
5
6
7
8
li { float : left ; margin : 0 ; padding : 0 ;}
li a { float : left ; display : inline ; height : 38px ; text-indent : -10000px ; overflow : hidden ; background : url ( 'sprites.gif' ) no-repeat ;}
li.nav 1 a { width : 103px ; background-position : 0 -19px ;}
li.nav 1 a:hover { background-position : 0 -57px ;}
li.nav 2 a { width : 91px ; background-position : -103px -19px ;}
li.nav 2 a:hover { background-position : -103px -57px ;}
li.nav 3 a { width : 106px ; background-position : -194px -19px ;}
li.nav 3 a:hover { background-position : -194px -57px ;}

效果以下dom

002

能夠看出,當鼠標懸停在中間按鈕時,並無實現咱們想要的效果,這固然也是在乎料之中的。繼續分析,咱們但願鼠標懸停在中間按鈕時按鈕空間能夠佔據右側豎線的一像素,這時想到當:hover時,元素可使margin-left負一個像素,這樣中間按鈕就向左偏移了一個像素,爲了使它的物理大小不發生變化,再給它定義一個像素的padding-left,這樣該按鈕在邏輯上增大了一個像素,物理上卻沒有變化,經過修改CSS,讓:hover下背景定位向右偏一個像素性能

?
1
2
3
4
5
/*修改過的CSS*/
li a:hover { margin-left : -1px ; padding-left : 1px ;}
li.nav 1 a:hover { background-position : 1px -57px ;}
li.nav 2 a:hover { background-position : -102px -57px ;}
li.nav 3 a:hover { background-position : -193px -57px ;}

效果以下測試

003

這正是咱們要的效果。經測試,發現進行負值操做後IE6下面出現bug優化

004

乍一看,咱們的css沒有生效,其實否則,爲了解決此bug,按鈕元素須要加上position:relative;

?
1
li a { position : relative ; float : left ; display : inline ; height : 38px ; text-indent : -10000px ; overflow : hidden ; background : url ( 'sprites.gif' ) no-repeat ;}

這樣,此bug就已經被修復了,IE6下顯示正常。(對此bug的產生緣由並無深刻研究,請高手補充)

到此,咱們須要的效果就已經實現了。

等等!若是僅僅只是到此,這不過是一個小技巧而已,並無什麼。其實好戲纔剛剛開始!

淘寶新的Sprite解決方案

在研究淘寶代碼的過程當中,發現它用了一個怪異的文檔結構,以下圖

005

能夠看到,它沒有用咱們經常使用的<li class="nav1"><a href="#">1</a></li>方式製做按鈕,而是採用了img圖片,src中的地址正是用來作Sprite的背景圖片。就在我對此百思不得其解的時候,猛然想起曾經看過的一篇關於瀏覽器對圖片加載順序的文章,我恍然大悟,難道它這麼作是與此有關?

補充,若是稱傳統Sprite技術爲CSS Sprite的話,該技術則爲IMG Sprite

立刻進行測試,文檔結構以下

?
1
2
3
4
5
6
< ul >
     < li class = "nav1" >< a href = "#" >1</ a ></ li >
     < li class = "nav2" >< a href = "#" >2</ a ></ li >
     < li class = "nav3" >< a href = "#" >3</ a ></ li >
</ ul >
< img src = "37.jpg" />

結果以下

006

結果果真如預期所料,因爲瀏覽器渲染時認爲img爲內容,而background只是修飾,因此在加載時,瀏覽器會先加載img圖片,而最後才加載background的圖片。瀏覽器這樣認爲,從邏輯上來說是對的,但在實際運用中,咱們每每會把導航作爲最重要的部分,並且但願它可以最快的加載出來。因爲瀏覽器的這個特性,咱們每每不得不接受在加載大量img圖片以後纔看到導航緩緩出現,若是background在導航中僅僅只是修飾做用還好,若是像此例般,描述性文字是存在於圖片中,繼而讓瀏覽者面長時間對空白等待,這就不可接受了。

通過上述分析,再回過頭來從新看淘寶的結構,便能明白他這樣作的良苦用心。

按照淘寶的風格,從新定義文檔結構以下

?
1
2
3
4
5
6
< ul >
     < li class = "nav1" >< a href = "#" >< img src = "img/sprites.gif" /></ a ></ li >
     < li class = "nav2" >< a href = "#" >< img src = "img/sprites.gif" /></ a ></ li >
     < li class = "nav3" >< a href = "#" >< img src = "img/sprites.gif" /></ a ></ li >
</ ul >
< img src = "37.jpg" />

再次測試

007

一樣,結果與預料中同樣,它按照咱們想要的順序來執行加載。至於CSS一樣是使用margin負值,並沒有太多新東西,直接貼出

?
1
2
3
4
5
6
7
8
9
10
11
12
li { float : left ; margin : 0 ; padding : 0 ;}
li a { position : relative ; float : left ; display : inline ; height : 38px ; overflow : hidden ;}
li a:hover { margin-left : -1px ; padding-left : 1px ;}
li.nav 1 a { width : 103px ;}
li.nav 1 a img { margin : -19px 0 0 0 ;}
li.nav 1 a:hover img { margin : -57px 0 0 0 ;}
li.nav 2 a { width : 91px ;}
li.nav 2 a img { margin : -19px 0 0 -103px ;}
li.nav 2 a:hover img { margin : -57px 0 0 -103px ;}
li.nav 3 a { width : 106px ;}
li.nav 3 a img { margin : -19px 0 0 -194px ;}
li.nav 3 a:hover img { margin : -57px 0 0 -194px ;}

效果一樣是正確的,IE6一樣(這裏有一事不解,若是不對li a:hover進行定義,li.nav1 a:hover img的定義在IE6下便會失效)

003

到此,這個效果算是大功告成了。

固然,採用此方法也有弊端,因爲按鈕使用的是圖片,在禁用CSS或WAP下瀏覽,瀏覽者就會由於圖片沒有進行過定位的整張Sprite圖片而感到迷惑。固然,在一般狀況下這種方法所帶來的性能優化與所付出的代價相比是值得的。

後記

本文是我認真寫的第一篇博文,並無參考過多前輩的文章,因此此方法或許早有人推而廣之了。在這裏仍是要感謝淘寶的UED們,大家的做品讓我收穫不已。同時以上分析僅僅是個人一家之言,或許淘寶他們之因此這麼作還有其它理由,或許只有淘寶的UED們纔講得清了。最後,以上分析若有錯誤,請多多指正。

關於元素加載的更多內容參看個人轉載:http://hi.baidu.com/gdgd8760/blog/item/710910d3ac4750c8a8ec9a30.html

感謝radom童鞋的補充,關於Img Sprite的其它優點請參看文章:http://www.cnblogs.com/radom/archive/2011/05/18/2050

相關文章
相關標籤/搜索