最近在處理Qzone黃鑽圖標更新時,想起近期對業務圖標進行優化所遇到的一些問題,把思緒收拾起來和大家一共探討,歡迎多方聲音。
在實際工作中,圖標類的應用非常廣泛,如同數組般的等級圖標更顯其特殊性。下面要共同探討的兩個方向,以什麼方式實現及怎麼更好在貼近項目實際更好地實現並供應用。
假設:業務的用戶等級共有10個,加上大小2種視覺尺寸的圖標,還有“過期未續費用戶”的表現,共有38個圖標需要入庫供調用(如下圖)。
在項目的CSS框架研發中,會有幾個key作為考慮:請求數、代碼量、兼容性、圖片文件大小、是否可並為組件模塊且方便邏輯性實現。
- 眾多不同等級的圖標在不同方式的廣泛應用時,是否會產生過多的文件請求;
- 等級圖標的代碼在實現上是否會使用過多的代碼,且頁面上真實應用的只是少量代碼,從而造成代碼臃腫;
- (x)Html+CSS輸出的圖標應用到頁面中,是否和頁面上其它元素兼容,否則將為達到兼容目標而增加一系列代碼;
- 如果各圖標合並後,權衡項目應用的實際情況,圖象文件是否會過大而消耗帶寬;
- 圖標的Html固定,className命名中的某個數字命為作為變量,通過修改變量來達到表現效果。
回顧之前的出現的處理方式,可以歸總為三種:
- 前景圖的插入
這應是最原始的處理方式了,將眾多單個等級的圖片有序命名存放到一個目錄,由前端頁面應用,通過修改文件名的方式更換不同的等級顯示。在實際的用戶列表頁面中,因為不同的用戶通屬不同的等級,那麼,就會顯示不販等級圖標,如上面假設,就會同時產生38個請求。且在項目的維護上,極易存在瓶頸。假設根據需目需要對圖標文件更換存放目錄或更改其尺寸大小,那麼需要大面積對所有應用過的開發 template文件排查處理(更改URL,寬高定義,文件名等),很多情況難以維系在可控范圍。
- 透明圖+背景的實現
這是Qzone項目中使用最多的一種方式,在項目的訪問速度體驗優化及圖標實際應用中起到不可磨滅的作用,該方式後期也陸續為國內外其它網站使用。其具體實現方式是,保存一張1*1像素的透明圖片,並將其設置長時間cache,因其display屬性的特殊性,圖片在頁面布局上得心應手,且解決了多請求的問題,同時解決圖片合並區域擴展維護的問題。但是,一旦在客戶端cache文件隊列中被擠掉,cache失敗,該方式容易讓這張透明的前景替位圖產生洪水式的請求, 造成服務器壓力和大流量。且<img />容易繼承項目中其它定義。在圖標與文字的垂直對齊上各浏覽器的渲染解析不一樣,從而增加一些兼容代碼。
也有衍生出來空src的處理方式,如<img src=”" class=”app_icon” alt=”icon” />,表面上看,可以節省文件的請求,但事實上,它除了會導致大量的無效請求外,還會向日給apache不斷寫入錯誤的log,造成過大的服務端壓力,同時,在非IE浏覽器(如Firefox)也會表現出缺省圖象的紅叉。
- 內容標簽+背景
這裡說的是帶文字等內容的標簽加入黃鑽等級圖標背景來實現,如<span>我是黃鑽7級用戶</span>,給span的左邊定義一個圖標,把文字向右移動一定的位置。大伙在實踐中驗證,這種在語義上和實現上,可以說是完美的了。但是,不方便項目代碼的規劃和管理,特別像等級圖片這類的可以歸入庫的代碼及應用方式。同時,標題的大小區域為不可控,在後續的維護中,更會不定期更改其區域大小,那麼,就在圖片的合並上存在瓶頸,難以確定一個圖片該預留多大的透明區域,使之不影響到其它場景的圖片應用,也可能會因為後期的維護處理不當,影響到其它標簽區域的背景顯示異常,造成不良的用戶體驗。
- 標簽載體+背景
結合前幾點所述,用一個標簽作為圖片的載體,再給它定義背景等屬性,顯示出相應的圖標。它既可以免除用圖片處理產生的流量和請求及服務器壓力,又減去合並圖片時所考慮的預留空間尺寸。一般標簽不具img的特殊屬性,既能成塊狀顯示出圖標,又能和文字等共處一行內,那麼在選取的這個標簽要在樣式上定義得較少,不易繼承樣式影響表現,破壞頁面的兼容和庫文件的管理維護。
在實際項目中,選用了strong作為圖標的替代標簽:
回顧完各種處理方式後,一起來了解一下實現上的細節,分析一下文章第一張圖所示,共有38個圖標,且都是圖形化,原始想法是,把38個圖合並成一個文件。但細心看,這38個圖片,有好多的相同的圖形,經過整理後,得到下面這張圖:
除四個圖標載體外,數字都是相同的,因為這裡使用的是第四種處理方式,那麼在圖標的合並上,不用給各小圖片塊預留過多的透明區域。
雪碧圖處理好以後,就可以著手寫代碼來實現效果了。
<strong class="gb_vip_1"><span><span>lv1</span></span></strong>
<strong class="gb_vip_2"><span><span>lv2</span></span></strong>
為了讓標簽具有img的特有屬性,給strong定義display:-moz-inline-stack;display:inline-block;
因各浏覽器兼容性的原因,需要定義了兩個屬性,這裡不禁一定要問了,為什麼不選用-moz-inline-box呢?這裡選用-moz-inline-stack而非-moz-inline-box的原因是:
- 使用-moz-inline-stack可以解決Firefox2不支持inline-block的問題,但是所有的Firefox版本對於屬性為-moz-inline-stack的Element,它的First child element會繼承該Element的寬度和高度,但是再下一級的Element不會再繼承該屬性。
- 這裡說說一下與本圖標應用無關的話題,在實際應用中-moz-inline-box會存在元素間的對齊等問題,在處理自適應寬的<button>就能遇到。雖然Firefox有一個私有屬性-moz-box-align來幫助解決Element水平對齊問題,但未能預見的問題依舊不少,而相對來說-moz-inline-stack的表現更像inline-block,這點可以在Firefox3中驗證出來。僅管如此,-moz-inline-stack使用時也會有一個bug,如果一個moz-inline-stack的Element外層Element是inline屬性就會使Firefox中其包含的鏈接不可點(和IE6的filter+position:absolute出現的BUG一樣),這個可以借助position:relative;來解決。
設置完display屬性後,我們就給圖標定義寬高。實際的圖標處理中,完成這兩步基本就OK了。但是這個圖標應用較為特殊,因為它是兩個背景合成一個圖標的(載體+等級數),如下圖:
下面是兩個載體的拼合示意:
所以在結構上加多了兩個span,一個是給等級數字的背景載體,另一個是隱藏圖標替換文字。
代碼寫完後,發現代碼量相當的驚人,因為只在最外層定義不同的className,那麼,就意味著,我們要對眾多個類及其裡面的標題定義:
.gb_vip_1 span,
.gb_vip_2 span,
.gb_vip_3 span,
.gb_vip_4 span,
.gb_vip_5 span,
.gb_vip_6 span,
.gb_vip_7 span
這樣代碼就相當臃腫,於是,改變className的定義方式,給各個等級圖標最外層容器定義相同的命名,給裡面數字的載體定義區別顯示的命名(帶數字的命名是方便邏輯實現):
<strong class="gb_vip_icon"><span class="lv1"><span class="gb_vip_none">lv1</span></span></strong>
<strong class="gb_vip_icon"><span class="lv2"><span class="gb_vip_none">lv2</span></span></strong>
以上所述的供討論和參考,期盼大伙一些其它的想法和分享。