新年伊始也來談談Webfont

開篇

隨著設備終端的不斷升級,瀏覽器的支持度越來越高。網頁字體的流行也是必然的趨勢,他的可選取,可搜索,可縮放,適配度高以及高性能、良好用戶體驗等優勢讓它一躍成為網頁前端們實現設計師天馬行空的設計圖的首選。

今天我們就來介紹一下Webfont及其應用,順便講講怎麼優化Webfont

介紹

簡而言之,Webfont就是可以讓網頁使用在線字體的一種技術手段。在此之前設計師在設計稿當中使用的一些特殊字體由於在別人的設備里沒有這個字體而無法顯示預想的效果,我們的解決方案是用圖片來替換特殊字體,webfont的出現這個問題就引刃而解了。

它通過 CSS的@font-face語句引入在線字體,使用CSS選擇器指定運用字體的文本。目前網路上使用的字體格式有四種EOT、TTF、WOFF 和 WOFF2

支持情況如下:

  • WOFF 2.0 提供給支持它的瀏覽器(對許多瀏覽器來說尚未實現)。
  • WOFF 支持大多數瀏覽器。
  • TTF 支持舊 Android(4.4 版以下)瀏覽器。
  • EOT 支持舊 IE(IE9 版以下)瀏覽器。

註:從技術角度來講還有一種格式,即SVG字體,但IE和Firefox從不支持它,並且好像現在的Chrome也放棄了對他的支持,所以暫且就忽略它了。

font-face

css3推出了一個at-rule屬性@font-face,來指定特定字體資源的位置、樣式特性及其支持的 Unicode 子集。

語法如下:

@font-face {n [ font-family: <family-name>; ] ||n [ src: [ <url> [ format(<string>#) ]? | <font-face-name> ]#; ] ||n [ unicode-range: <urange>#; ] ||n [ font-variant: <font-variant>; ] ||n [ font-feature-settings: normal | <feature-tag-value>#; ] ||n [ font-variation-settings: normal | [ <string> <number>] # ||n [ font-stretch: <font-stretch>; ] ||n [ font-weight: <weight>; ] ||n [ font-style: <style>; ]n}n

  • font-family: 指定字體的名字,所指定的字體名字將會被用於font或font-family屬性;
  • local() 指令用於引用、載入和使用安裝在本地的字體;
  • format(): 通過該屬性來指示URL資源引用的字體格式(可選);
  • unicode-range: 指定要使用的字體的Unicode子集,從而減小字體載入的體積。

特殊數字字體

比如上圖設計師想要的結果,騷氣的科技感數字我們要使用DIN字體,但是DIN字體不是所有設備都支持所以我們打算讓他支持:

@font-face {n font-family: DIN;n font-style: normal;n font-weight: 400;n src: url(../assets/font/DIN_Alternate_Bold.eot);n src: local("DIN Alternate"),n url(../assets/font/DIN_Alternate_Bold.woff) format("woff"),n url(../assets/font/DIN_Alternate_Bold.ttf) format("truetype"),n url(../assets/font/DIN_Alternate_Bold.svg#DINAlternateBold) format("svg")n}n

當瀏覽器察覺到本地沒有DIN字體的時候,他會按照指定的順序循環訪問提供的資源列表,如果存在一個format格式提示則先檢查是否支持,如果支持就載入該資源,如果不支持則跳過進入下一個格式提示,如果不存在格式提示則不論如何會嘗試載入相應的資源。

性能優化

壓縮

字體是字形的集合,其中的每個字形都是一組描述字母形狀的路徑。每種不同字形,往往包含了大量的共同信息,這些信息是可以壓縮的。

常見的壓縮方式是:GZIP及其他兼容的壓縮模式:

  • EOT 和 TTF 格式默認情況下不進行壓縮,你可以在伺服器開啟GZIP進行壓縮;
  • WOFF 具有內建壓縮
  • WOFF2 採用自定義預處理和壓縮演算法,提供的文件大小壓縮效率比其他格式高大約 30% , 你可以選擇其他的壓縮方式來減小字體的體積,但要注意做好瀏覽器測試。

unicode-range

利用unicode-range指定編碼子集,可以大大減小字體的體積。使用方法有:

  • 指定單一的字元編碼用逗號隔開(例如 U+416)
  • 間隔範圍 用橫杠- 表示代碼的起始,例如 (U+400-4ff)
  • 通配符(例如 U+4??)?代表任何16進位數字

上述三者可以配合使用,並用逗號隔開。

註:有時候有些瀏覽器對unicode-range支持的不好,這個時候我們就需要對所使用的字體進行手動的選取子集。網路上很多第三方工具 如fonttools 字蛛等。

font-display

註:這是最新的屬性,還沒達到可使用標準(目前Safari還不支持,Chrome部分版本支持)

這是最近剛剛提出來的一個方案,就為了解決字體渲染空白問題,說這個之前我們先來講講網頁字體的載入和渲染問題。

主要誘因是瀏覽器在構建渲染樹(DOM和CSSOM樹)之前會延遲字體請求,因為瀏覽器必須構建萬渲染樹之後才能知道使用哪些字體來渲染文本,同時在獲取到構建渲染樹關鍵資源之前可能會阻止瀏覽器渲染文本(網頁內容的首次渲染和字體資源載入之間的「競賽」時,瀏覽器會產生遺漏渲染所有文本的渲染 注意是所有)。當然對於空白問題在不同瀏覽器的表現不同,比如Safari會在字體下載完成之前都阻斷文本渲染,而chrome會等待最多三秒開始啟用後背字體並在下載完成後重渲染。總結下來就下面這個圖:

字體渲染關鍵路徑

Block階段瀏覽器使用不可見字體渲染文本(出現空白渲染);到了Swap階段瀏覽器使用後備字體(sans-serif)渲染文本;在Failure這個階段意味著字體下載失敗,瀏覽器將一直延用後背字體。

目前的問題在於我們沒法控制這些階段的時間長短以及當其中一個階段失敗後怎麼處理,font-display給了這種可能。它有四個值:block, swap, fallback 以及 optional,當然也有auto其表現和block一致。

各個屬性值表現如下圖:

    • font-display: block ,文本將被阻斷一段時間(長短看瀏覽器,新版Safari, Chrome ,Firefox是3秒;IE為0秒可視為沒有block階段;舊版本Safari無限長時間),會出現所謂的空白渲染問題(FOIT)
    • font-display: swap ,文本將不會出現block階段,文本會立即用後背字體展現知道所需字體載入完成。會出現字體切換效果(FOUT)
    • font-display: fallback ,表現介於block和swap之間。空白期縮短至100ms,然後切換到後備字體直到所需字體載入完成
    • font-display: optional ,表現和fallback類似,區別在於它會自動的去根據網路的速度(如2g網路)來決定是否切換字體。

此屬性使用時,我們需要根據具體情況來使用:如果我們使用webfont來做icon圖時候,我們是不可能接受fallback的,所以我們需要使用font-display:block。

更多

想要說的是@font-face 里提到的屬性(如font-weight,font-style等)對於性能優化來說也是很重要的,他會影響瀏覽器匹配資源和載入資源的效率以及視覺一致性等因素,所以儘可能準確的給瀏覽器於明確的指示。

當然了其他的優化方案還有很多,包括HTTP緩存,利用FontLoading API優化起載入和渲染等自行探索吧。

結語

2017年過去了,本來想寫個總結的。但人在歐洲的火車上,思緒全不在這上面。眨巴眼的功夫2018年已經悄然開始三兩天了,雜貨鋪開篇也快兩年了,由於17年後期也懶了許多文章一直沒跟上,粉絲也沒達到年初一萬的小目標,但也9910有餘,專欄共收錄文章112篇(算上這,113篇)。在此感謝作者 @天方夜, @於秋 , @謝然 , @染陌同學, @蔣歡, @林鑫, @SimplyY , @Awee, @鬍子大哈, @吳成琦, @LeviDing , @黃俊亮 , @林列歡 , @Ahonn 等(排名不分先後,可能有紕漏見諒)的投稿,為熱愛前端的同學們帶來知識的饕餮大餐,沒有你們的支持雜貨鋪也不會受到如此多關注。同時也感謝成千上萬的粉絲一如即往的支持,你們是我堅持的動力。在知乎里遇到大家是我的榮幸,希望在接下來的一年裡我們能延續這樣的默契和友誼,為了這份純粹的愛好共同進步。


推薦閱讀:

阿里媽媽前端技術周刊 2018-01-12
一篇文章讓你知道被 Google 攻破的 SHA-1 是什麼
你不需要基於 CSS Grid 的柵格布局系統

TAG:前端工程师 | HTMLCSS | IconFont |