數年前寫過一篇很實用的文章,介紹了一個很有創意的技術:「CSS背景色鏤空技術實際應用及進階」,講的圖標圖形為了更容易控制其顏色,對圖片採用了鏤空的處理。例如,下面這張圖片(點擊會有隨機的背景色):
於是,我們只要一套圖片就可以實現各種顏色效果了!
而不要類似下面這樣,為了各種狀態湊齊完整的葫蘆七兄弟:
除了節約圖片資源大小,CSS鏤空圖片技術還有一個好處,就是由於我們的圖標顏色是CSS屬性控制的,因此,我們可以漸進使用transition實現過渡效果,讓交互更細膩。
說到CSS控制圖標顏色,我們自然而然會想到icon fonts, 或者使用SVG sprites技術,或者使用混合模式來實現。
然而,都是有不足的,比方說:
SVG的兼容性以及混合模式的理解成本和環境限制等。
因此,轉了一圈,會發現,有時候,還是圖片來得最實在,且看下面demo實現的效果,雖然使用的是background-image實現的,但是hover態,selected態都和文字hover transition過渡,這是傳統背景圖片所沒法實現的。
一行:
transition: background-color .25s;
就可以讓交互變得細膩!
default, hover, selected三種顏色態僅僅一個系列圖片就搞定(見下圖),看上去很贊,贊到飛起來。
然而,這種實現有一個致命的不足,就是CSS的加載和背景圖片的加載不是同步的,尤其首次加載的時候,圖片是異步的,具有明顯的延遲,於是,我們會看到非常醜陋的色塊在一瞬間出現了(大家可以強刷demo體驗到)!
正所謂「開發可忍設計不可忍」,這種問題顯然是非常嚴重的,直接導致此看上去很酷的方法瀕臨夭折的邊緣,看上去只適用於默認隱藏的元素。
大家莫慌莫慌,有我在呢!
二、base64 url圖片與異步色塊問題解決這個很好理解,就是把背景圖片轉換成base64 url圖片,因為是集成在CSS文件中的,因此,基本上是同時呈現,不會出現色塊。然而,此方法局限性很明顯,就是只適用於一些尺寸很小的小圖。類似上面demo的背景圖片,有5K多大小,直接內嵌在CSS文件中,就像是身體裡長了個瘤子,太笨重了,而且base64渲染是比較燒性能的,圖片越大越慢,且IE7瀏覽器很難支持base64圖片。
因此,此方法在這裡不適用,難道要天亡我也?非也!
三、content url圖片與異步色塊問題解決6年前,也就是10年的時候,我在「CSS content內容生成技術以及應用」一文中首次介紹了CSS content url圖片內容生成技術,就是before, after偽元素可以直接插入圖片,注意,是直接圖片,不是元素的背景圖,語法如下:
.demo:after { content: url(xxx.png); }
OK, 大家如果觀察過頁面圖片的加載,應該注意到這麼個現象,就是如果圖片沒有通過HTML屬性或者CSS值限定width/height寬高的時候,在瀏覽器get到圖片的原始尺寸之前,圖片佔據的空間大小是0. 我們如果刷新浪微博,會發現頁面高度蹭蹭蹭地往上漲,就是這麼個原因,這種不對圖片限定尺寸的做法在網頁布局中是不推薦的,因為,會造成頁面布局重繪,影響加載性能。
但是,存在必有道理,在這裡,我們就可以好好地利用圖片為加載時候佔據空間為0的特性避免出現色塊的問題,怎麼解決呢?就是把元素的background-image url值變成偽元素的content url值;同時background-position定位改成其他定位,如relative定位,如下代碼示意:
.icon { width: 140px; height: 140px; background: #c8c8c8 url(icon.png) no-repeat 0 -140px;}↓.icon { /* 注意,只設高度不設寬度 */ height: 140px; background-color: #c8c8c8; overflow: hidden;}.icon:after { content: url(icon.png); position: relative; top: -140px;}
上面綠色注釋「只設高度不設寬度」點出了實現的關鍵:
頁面渲染流程如下,1. CSS加載;2. 對應DOM渲染,背景色出現;3.拉取DOM樣式對應背景圖片。
傳統實現就是從2到3的時候出現了問題,圖片從伺服器重新請求,導致了時間差,出現了色塊。而我們這裡的實現就不一樣,當我們背景色出現,但是圖片未加載的時候,由於我們的CSS沒有設置元素的寬度,加上圖片未加載佔據寬度為0的特性,於是,在2完成3即將進行的時候,我們整個元素的高度140px, 寬度0,寬度是0啊!這意味著什麼,意味著元素看不見啊,也即是雖然有背景色,無奈尺寸為0,我們是看不出有一絲絲背景色的;然後等圖片請求到,自然就填滿了元素,背景色也被遮掉了。沒有了時間差,於是,完美解決了色塊出現的問題!
IE7瀏覽器
什麼年代了,還IE7瀏覽器,要是喜歡,可以使用expression表達式,或者直接JS打個補丁,小弟我現在對這些瀏覽器不奉陪了!
我測試發現,時間差似乎就Chrome瀏覽器比較明顯,另外後面的content url有一定機率會出現最後一個有色塊的情況,按照道理應該不會的,現在太晚了,都2點了,我有時間在研究研究。
更新於翌日
趁下班,研究了下為何有一定概率最後1~2個圖片會有色塊。我刷了幾十遍感受了下,尼瑪恍然大悟。原來,圖片是自上而下加載的,有背景色的時候,只是圖片尺寸得到了,但是,數據還沒完全下載下來,於是,此時,受制於網速原因,圖片上面加載好了,下面可能沒加載好。類似下面:
我之前有介紹過,可參見「漸進式jpeg(progressive jpeg)圖片及其相關」。
哈,知道了問題的原因,就知道該如何解決了。PS保存圖片時候,JPG是選擇連續,而PNG則是交錯:
我已替換原來圖片,現在,大家就真正不會出現一點點色塊了。
現在的小問題就是PNG壓縮同時保持交錯該怎麼處理,稍等,我再研究下~
更新於2016年2月28日
趁周末有研究了一下,一些壓縮工具,甚至包括Fireworks,都沒有看到png8 alpha格式同時支持交錯模式。高手在民間,希望有知道該如何處理的小夥伴不吝賜教!
PS: demo背景圖現在又換成png8 alpha壓縮圖了,省點流量~