隨著硬體快速的發展,Retina技術發展至今,目前Google Nexus6的devicePixelRatio已經到了3.5,雖然目前主流的Retina顯示器還是以devicePixelRatio = 2的為主,但是為了更好的使用者體驗,前端和視覺同學經常都要為了各種圖示能夠在Retina螢幕下高清顯示而頭痛。下面先介紹下目前的一些常規的解決方案。
1.多倍圖片
目前用的比較多的做法是相容devicePixelRatio = 2 就做實際圖片大小的兩倍,devicePixelRatio= 3就做三倍,有些人可能會直接做3倍的圖片,這樣就可以同時相容devicePixelRatio = 2 ,但是這樣其實對於devicePixelRatio = 1和devicePixelRatio = 2的使用者他們就會浪費頻寬去載入devicePixelRatio = 3的圖片,所以為了提升使用者體驗,一般我們會分開做幾套圖片,根據用使用者的devicePixelRatio判斷讓他們載入對應的圖片。
2.iconfont字型圖示
在很多國外的響應式站點裡一般會採用iconfont,因為可以直接通過font-size和color屬性來控制icon的大小和顏色,非常方便,而且由於iconfont本身就是字型檔案,會向量適配各種不同devicePixelRatio,但是在PC上當圖示小於等於16px時,或者複雜度高的圖示會出現比較嚴重鋸齒,圖示無法展示清晰,特別在chrome下的表現尤為嚴重。正因為如此這個技術在推進過程中遇到許多困難,因為在很多場景下圖示確實會較小甚至小於16px,而且有些16px的圖示如果複雜度較高,iconfont實現出來的icon會經常出現看不清的情況,而且國內PC使用者是佔最多的,所以iconfont的這種表現效果很多使用者和設計師無法接受。
為什麼iconfont會出現鋸齒?
這個問題其實並不是iconfont的錯,但很多人都覺得是它的問題,關於鋸齒問題,我們先來了解下瀏覽器的字型渲染機制,阿里有篇文章《字型圖示製作詳解》裡有一部分關於早期字型渲染機制的說明,內容如下:
(從左到右依次)理想的渲染狀態、黑白渲染、灰度渲染、次畫素渲染上圖左側第一張是我們認為一種比較理想的渲染效果,但是通過剛才我們介紹柵格我們可以瞭解到這種狀態是不可能的,因為第一代黑白渲染和第二代灰度渲染是不可能做到顯示半格畫素或一個畫素中顯示弧度的。
黑白渲染和灰度渲染在渲染圖形遇到半格畫素或則弧度的時候,他們會有各自不同的處理方式;
舉個例子:
如上圖紅點處畫素,我們理解他是有弧度的,且不佔滿一個畫素;各個渲染方式的處理辦法如下:
黑白渲染
黑白渲染相對來說比較粗暴,直接通過四捨五入的形式把這裡要描繪的圖形不顯示了;(黑白渲染的形式主要應用於印表機渲染,但是印表機本身的精度非常高,所以列印出來的圖形還是很細膩的)灰度渲染
灰度渲染顯得就智慧一些了,他通過灰度降級的方式來表達,如果佔不到一個畫素那就根據他佔的面積來降低這個畫素的灰度;佔的面積越小灰度就越低;次畫素渲染
次畫素渲染是第三代渲染方式,相對來說比較高階,他從從左至右將一個畫素分成三份;用不同的色彩值來顯示圖形,這樣圖形看起來就更加細膩;
現代瀏覽器字型渲染技術
目前mac系統採用的就是次畫素渲染技術,但是現代的window下的高階瀏覽器例如:IE9+ 、chrome、FF等瀏覽器採用的是 DirectWrite 或 GDI 這種更高階的字型渲染技術,這裡我簡單介紹下這兩種新的字型渲染技術:
上圖從左至右分別用的是:灰度渲染、次畫素渲染和 DirectWrite 或 GDI 實現的效果,在FF官方部落格中有一篇文章對這兩個新的渲染技術做了簡單的一個解釋,他們兩個都是採用的LCD的畫素紅色、綠色、藍色來進行畫素填充,右側的文字被放大後我們看到了字型柵格被不同色塊填充,其實人眼對於亮度差異非常的敏感,當這些顏色用在畫素級別裡面我們的眼睛往往認為字形比單純灰度消除鋸齒的效果更好。
在Windows下的Firefox 4中採用的就是GDI這個技術進行字型渲染的,但是到了Firefox 4+之後的版本開始使用了DirectWrite這個技術,官方解釋是說DirectWrite支援硬體加速,而且API也更加現代,而GDI API存在許多缺陷和問題。
關於DirectWrite和GDI他們之前的差異這裡不作太多描述,在文章最後有相關文章連結,有興趣的同學可以檢視下。上面講了字型渲染的歷史,我們現在來看看目前Windows系統下的瀏覽器各自都是採用的都是什麼字型渲染機制:
Chrome目前依舊是使用GDI,而FF和IE9+已經是採用了DirectWrite,這就是為什麼iconfont在Chrome下鋸齒會比其他瀏覽器嚴重的原因,可能GDI確實像FF官方說的存在許多缺陷,不知為何Chrome至今還在繼續使用這個技術。
上面說了這麼多關於字型渲染機制原理,在這裡能得出一個結論: 不管目前使用什麼字型渲染技術,字型顯示效果始終是會出現鋸齒的。在Retina螢幕上,一個畫素被拆成了4個畫素,由於它的密度非常高,肉眼根本是看不出鋸齒的,所以現在MAC系統下的FF和Chrome都還是用的次畫素渲染這項技術。既然iconfont他是一個字型,就難逃出現鋸齒的命運,特別在Chrome下就是更加的糟糕了,目前確實通過前端程式碼也是無法改變這個缺陷。
iconfont由於這個嚴重的鋸齒缺陷導致一些大型的站點很多時候並不會考慮大規模使用它,例如QQ空間,騰訊雲這些站點早期也都嘗試過iconfont方案,但最後都放棄了,為了能給使用者更好的感官體驗。像淘寶雖然目前有許多地方都用了iconfont但也只是區域性使用,並非全站使用。
SVG技術
什麼是SVG? SVG可縮放向量圖形(Scalable Vector Graphics)是基於可擴充套件標記語言(XML),用於描述二維向量圖形的一種圖形格式。SVG是W3C制定的一種新的二維向量圖形格式,也是規範中的網路向量圖形標準。SVG嚴格遵從XML語法,並用文字格式的描述性語言來描述影像內容,因此是一種和影像解析度無關的向量圖形格式。簡單的說他就是一個可伸縮向量圖形 (Scalable Vector Graphics),在瀏覽器中採用繪圖技術。
接下來我們來看看使用iconfont和使用SVG做出來的圖示有什麼差異:
上面的demo分別在不同瀏覽器下的效果,第一行用的是iconfont實現,下面三行都是用的SVG實現的圖示,只是呼叫SVG時的方法不同:第一行是用inline SVG,將SVG直接寫在html中來使用,第二行是用的img標籤去呼叫SVG,第三行用樣式的background來呼叫SVG檔案。從Chrome和FF下的顯示效果,我們看到SVG畫的ICON的質量確實是比iconfont要好,iconfont做的圖示,我截圖後放大後看到線的邊緣發虛了,這是因為字型渲染的原因導致,在FF下也是發虛,只是不那麼明顯。在IE9+下的效果上我們看到IE對SVG的支援性著實差的令人無法直視,IE10,IE11效果和IE9幾乎一樣(真的是坑爹)。
如何繪製高質量ICON
在上面的demo中眼尖的同學應該可以看出在FF下,inline SVG圖示有一個出問題了,然而Chrome卻是正常的:
但左邊那個圖示卻是正常的,相當不科學,如果是渲染問題理應左邊的也發虛才對,但是卻只有右邊的出問題了,定位了很久問題出在哪裡,最後發現是畫AI檔案時出問題了,AI本身不像PS那樣,有網格輔助視覺畫圖,所以iconfont.cn出了一個AI模板,其實這套模板就是給AI畫了一套輔助線,幫助設計師按照柵格畫ICON,我前面的案例就是用的他們提供的模板畫的圖示,第一個沒問題,但是第二個出問題了。他們這套AI模板實際匯出後的畫布大小是1002px1002px,然後分成16*16個格子,也就是每個格子實際分得62.625px*62.625px,其實在很多時候貌似不會出問題的,但是我的demo中卻出問題了,於是猜測:
- 是否是繪製圖示出問題了,沒有按照某種規範畫法?
- 是否是因為他的網格不能被整除導致的?
1、由於繪製這個鎖型的圖示時我們留下了一個單數列,會不會因為這樣導致了他出現鋸齒,如果是,那問題就來了,如果一定要左右對稱或者每次畫圖都要鋪滿所有格子,這種做法不太現實,因為很多圖示是不一定都全部能鋪滿16*16的格子。
2、發現iconfont這套模板的網格有些問題,畫布網格竟然有1px畫素是留空的,也是說16格子其實是1001/16=62.5625px,雖說畫布是1002px,不知道這是否是人工失誤。
決心和視覺自己做一套AI模板,AI模板也是16*16的網格,但是每個網格將他們的實際匯出畫素設定成1px,也就是整個畫布是16px*16px,這樣的就不怕不會被整除了。然後用新AI模板重新做了三個圖示,進行測試,左右上下對稱的做了一個,不能左右對稱的做了一個,左右上下不能對稱的也做了一份。,然後匯出效果檢視:
按照這套模板做了圖示後,FF下面三個圖示都是完美的,沒有出現虛邊,並且Chrome也同樣是完好的,這是我們希望看的的。也證實了上面的兩個問題猜測是正確的。所以這套AI模板是完全可以滿足不同場景圖示繪製。
小結:
本文介紹了字型渲染機制,並分析iconfont出現鋸齒的底層原因,再到如何繪製高質量SVG ICON的步驟和輸出了一套嚴謹的AI繪製圖示模板。
高清圖示SVG解決方案全總結(下)
將介紹如何在專案中應用SVG圖示,併相容IE6+ 、Chrome 、 FF 、Retina Safari 、 Retina Chrome等瀏覽器的方案。