Web字體應用指南最佳實踐修煉之道(上)

據說把名字取得特別長更容易被搜索到

故事的起源,要從UED界兩大種族前端設計師和視覺設計師的愛恨說起:

設計師的視覺稿
前端開發(fā)出來的真實效果
于是戰(zhàn)爭爆發(fā)了

像這種視覺效果不一致問題,在日常開發(fā)中比比皆是。最近遇到的比較多的是字體問題,開了寫輪眼的設計師經常抱怨手機上的字體跟設計稿不一致,前端只能無奈的回一句手機上沒這字體啊...然而實際情況遠比這個復雜,正義的王二小見此情況決定挺身而出,踏上了Web字體修真之路,來尋找傳說中的最優(yōu)解。

從0開始

這將是一次冒險,我們從0開始探索網頁中的文字是如何一步步呈現在我們眼前的。計算機的數據,本質上都是由01組成的序列,不同的序列可以傳達不同的信息,而同樣的序列通過不同的編碼和解碼方式也會傳達不同的信息。

我們所看到的網頁,都是從服務端網絡傳輸而來的一個個數據包通過瀏覽器解析而成,網絡傳輸其實是一個很復雜的編碼解碼過程,你可能聽過數據段,報文,分組,數據包,數據幀等關鍵詞,這些術語其實只是OSI模型中各個層對數據單位的不同劃分,最底層的表示還是以bit為單位的01。假設瀏覽器現在要渲染一段文本,它從服務端收到的數據包有一段信息是這樣的(當然為了簡化,除去報文頭等信息,假設下面這段信息就頁面上要展示的文本信息):

11100101 10001010 10101000 
11100110 10000100 10011111 
11100101 10110000 10001111 
11100101 10001001 10001101
11100111 10101011 10101111

這是一串字節(jié)流,瀏覽器得到它的第一件事自然是解碼,那么第一個問題,編碼方式很多種,瀏覽器怎么知道用哪種方式去解碼呢?

編碼與解碼

我們所熟知的編碼方式有ASCII,GB2321,UTF-8,UTF-16等等,對于瀏覽器來說,它會按照以下規(guī)則去尋找數據的編碼類型:

  1. Web 服務器返回的 HTTP 頭中的 Content-Type: text/html; charset="xxx"。其中charset="xxx"就是編碼方式,當瀏覽器拿到這個信息之后,就能愉快的解碼了;
  2. 如果服務端沒有指定編碼方式,瀏覽器會去網頁文件的head中查找<meta charset="xxx">信息,來確定編碼方式。
  3. 如果還沒找到,那瀏覽器就只能自行判斷編碼了,或者讓用戶設置解碼方式。

可以看到,前兩步信息都是確定的,只有第三步是無法確定編碼方式的。所以為了讓你的頁面能正常展示出來,一定得要在前兩步就設定好charset編碼方式,以便于瀏覽器以你期望的方式解碼。

現代網頁通常都使用utf-8的編碼方式,所以我們就以此為例。utf-8是unicode字符集的一種實現方式,unicode本質上就是一個表,一個將二進制數據映射到各種文字符號的表,這個表野心很大,想要囊括世界上所有文字符號,并且他也實現了自己的目標,所以它也成了網絡世界應用最廣泛的一個表。

假設上面那串字節(jié)流采用了utf-8編碼,那么根據utf-8字節(jié)流到unicode的編碼規(guī)則:

Unicode~UTF-8映射表

可以看到上面那段字節(jié)流全都是1110xxxx 10xxxxxx 10xxxxxx的形式,那么根據表中第三行映射關系,應該是3個utf-8字節(jié)對應1個unicode編碼,將三個字節(jié)中的16個x用兩個字節(jié)表示,然后轉化成十六進制的unicode表示,最終可得到以下結果:

11100101 10001010 10101000 -> 01010010 10101000 -> \u52a8
11100110 10000100 10011111 -> 01100001 00011111 -> \u611f
11100101 10110000 10001111 -> 01011100 00001111 -> \u5c0f
11100101 10001001 10001101 -> 01010010 01001101 -> \u524d
11100111 10101011 10101111 -> 01111010 11101111 -> \u7aef

得到unicode編碼之后,我們就可以根據unicode字符表找到對應的文字符號,最終得到了以下結果:

\u52a8\u611f\u5c0f\u524d\u7aef -> 動感小前端

如果對最終的結果不確定,可以反向驗證一下:

escape('動感小前端') // "%u52A8%u611F%u5C0F%u524D%u7AEF"

得出的unicode字符數值完全一致,看來計算沒錯,那么緊接著第二個問題來了,瀏覽器該如何去展示它?就好比我知道你的名字叫什么,但并不知道怎么寫一樣。

尋找字體

字體的渲染是一個很復雜的過程,首先我們需要知道在Web世界中存在著五大字體家族,江湖人稱font-family:serif、sans-serif、monospace、cursive和fantasy。在這五大家族下面,又演變出各個不同的字體,比如宋體,微軟雅黑,Arial,Helvetica等等。同樣的文字,在不同的字體下面會呈現出不同的效果:

相同大小粗細但不同字體的差別

但是,不管是什么字體,他們本質上都是一個表。你可以把這個表理解成三個部分:

  • 輪廓:用來記載字符的形狀;
  • 編碼:用來記載字符內部編號與字符形狀以及unicode編碼之間的映射關系;
  • 封裝:將上面這些東西封裝成特定的文件格式

想要深入了解字體內部原理,請走支線劇情《Fonts & Encodings》

瀏覽器在渲染字體時,首先會把這些文字分為不同語言的小段,然后依次確定該用哪一種字體,確定之后按照字符的unicode編碼在字體中匹配相應的輪廓,并最終渲染在屏幕上。通常我們都會給頁面指定一套字體規(guī)則:

font-family: Helvetica, STXihei, "Microsoft YaHei", Arial, SimSun,sans-serif; 

瀏覽器會按照字體聲明的順序依次去尋找系統(tǒng)中已安裝的字體,如果找到了就按照該字體渲染,沒找到則依次往后查找,如果最后還是沒找到,則使用瀏覽器設置的神秘的默認字體。

渲染排版

確定了字體之后,瀏覽器就真的要去渲染了。如果你以為把字體設置的一樣就能萬事大吉了,那就太天真了。即使是相同的字體,不同的環(huán)境下渲染出來的結果也是不一樣的!就好比同樣是須佐能乎,不同人產生的形態(tài)也是不一樣的,先看兩張圖:

相同字體在不同環(huán)境下的效果
放大后的對比效果

這是同一個頁面在不同環(huán)境下的顯示效果,其實如果在真實環(huán)境下看的話基本看不出來差別,但是對比一看差別還是很明顯的。MBP下是retina屏,顯示效果更細膩一些,而MBA下則更厚重些。放大來看,MBP下字體邊緣有灰色的邊緣(灰度渲染),而MBA下則是彩色的邊緣(次像素渲染)。

可以看到,同樣是Mac系統(tǒng)+Chrome瀏覽器,只是版本號稍微不同,渲染效果就會有所差別。更別說在Windows和Android上了。那么造成這種差異的原因是什么呢?

排版引擎

不同瀏覽器有著不同的渲染引擎,不同的操作系統(tǒng)上面也有不同的文字排版引擎,而瀏覽器在渲染頁面文本的時候都會調用系統(tǒng)的文字排版引擎。不同的排版策略就會造成不同的渲染結果。

Mac使用的排版引擎為CoreText,Windows7為DirectWrite/GDI,Windows XP則使用GDI。我們不會深入探索各個排版引擎的原理(想要深入了解Web字體渲染知識,可以去Typekit上了解更多),只需要知道不同的渲染引擎可能會造成字體有細節(jié)上的差異。即使是同一種渲染引擎,采用不同的渲染策略,比如灰度渲染和亞像素渲染,得出的效果也是不一樣的。

Core Text 渲染引擎
DirectWrite渲染引擎
GDI渲染引擎,開啟標準抗鋸齒
GDI渲染引擎,無抗鋸齒

由此可看出排版引擎渲染策略的差異是造成字體顯示效果不一致的根本原因之一,但是這種差異非常之小,對于普通用戶來說,根本不會注意到這些細節(jié),所以前端工程師大可不必為此操心。

至此,我們終于走完文字從0渲染到屏幕上的整個過程。

諸子百家

之前有提到,當瀏覽器沒有找到所聲明的字體時,會使用默認字體。問題就在于,這個默認字體到底是什么字體呢?不同設備之間的默認字體又分別是什么?影響默認字體的因素又有哪些呢?

在舊PC時代,統(tǒng)治人類的主要是windows和mac兩大陣營,我們扳著手指頭都能列出各大平臺和瀏覽器上的默認字體。但是到了如今的無線亂世,安卓的開源讓每個設備廠商都可能會有自己獨特的默認字體,這對網頁的視覺統(tǒng)一性又帶來了巨大的挑戰(zhàn)。

裸奔字體

裸奔字體就是你的頁面不設置任何樣式,瀏覽器呈現出的默認字體,我寫了個小demo,你可以點擊試試看你瀏覽器上面的裸奔字體是啥,也可以掃碼看看手機上的情況:

瀏覽器默認字體測試

CrossBrowserTesting上跑了一下效果如下:

Win8/OSX 部分瀏覽器對比

而在本人真機下的效果:

自上而下分別為Firefox,Safari,Chrome

很明顯能看出,裸奔字體千變萬化,根本不靠譜!

安全字體

好在,現在已經沒有人裸奔了,一般都會在頁面中手動聲明一下字體,比如百度首頁是這樣的:

body{font: 12px arial;} // 寫的這么精簡是為了省流量么...

谷歌首頁是這樣:

body{font-family: arial,sans-serif;} // 好歹加了字體族

天貓首頁是這樣的:

body{font: 12px/1.5 tahoma,arial,"\5b8b\4f53";}

淘寶首頁是這樣的:

body{font: 12px/1.5 tahoma,arial,'Hiragino Sans GB','\5b8b\4f53',sans-serif;}

上面四種寫法可能都有自己的考慮,但僅從終端字體表現的角度來看,很明顯淘寶的寫法更專業(yè)。Arial可謂是支持性最廣的字體了,所以大家都用上了,這種被大多數系統(tǒng)所默認支持的字體,就是Web安全字體。

CSS Font Stack上有對Web安全字體的整理,建議設計師們在作圖的時候多考慮一下,這樣能一定程度上降低視覺差異。并且某些字體其實長得還是蠻像的,你還可以使用安全字體來代替長相相似的非安全字體。

Arial支持性最廣,而Helvetica在Mac上100%支持

到目前為止,我們所做的一切考慮就是讓頁面字體效果在不同終端下盡可能保持一致,初步結論就是要使用安全字體,然而設計師并不這樣想。設計師一般會使用逼格比較高的非安全字體,比如蘭亭細黑,蘋方字體。一旦瀏覽器發(fā)現系統(tǒng)沒有這些字體,就會不斷降級,最壞的情況,就是一直降級到默認字體。所以通常我們會在font-family最后加上一個默認的字體族,比如sans-serif,這樣瀏覽器在最壞的情況下也能使用特定的字體族,并在該字體族下選擇一名指定字體來展示。

那么在這些指定的種族背后,被選中的孩子們到底都有誰呢?

神秘的默認字體

首先系統(tǒng)會默認安裝一些字體,維基上有對Win/Mac內置字體的整理:

然后當你安裝軟件時,有可能會附帶安裝一些字體,這樣你系統(tǒng)上能支持的字體又變多了。在上面那份列表中,Win/Mac共同支持的字體只有Arial, Verdana, Tahoma, Trebuchet MS, Georgia等少數Web安全字體,對于Win/Mac平臺實際字體效果分析,請參考此文:

跨平臺字體效果淺析:https://isux.tencent.com/5058.html

重點說下無線端, iOS FontsiOS Font List網站整理了一份各個版本的iOS字體清單,可以很方便的查出各版本支持情況:

Helvetica字體完美支持
蘋方字體從iOS 9 才開始支持

雖然方便,但畢竟第三方網站,不排除數據有誤的情況,于是附上官網聲明的字體清單:

對于安卓,原生的安卓使用的是Droid Sans(英文/數字)和Droidsansfallback(中文),4.0后修改為Google的開源字體Roboto。而非原生安卓,實在沒有總結性可言。比如小米和華為用了方正蘭亭黑,錘子則使用了華文黑體,并且同一廠商下的不同手機品牌,同一品牌的不同型號默認字體都可能不同,不做展開。

一張圖總結一下:

各平臺默認字體對比

哦,忘了還有Windows Phone,WP默認英文字體是Segoe,中文字體在WP8以前是雅黑,WP8之后是方正等線體。

哦,忘了還有YunOS,貌似是方正蘭亭細黑...

強大的自定義字體

是的,用戶可以選擇自己喜歡的字體。你永遠不知道用戶會干什么,什么安全字體,默認字體,一個主題包下來全都是浮云:

用戶修改系統(tǒng)字體

當然這不是最絕的,換個字體最多樣子變了,最絕的是用戶開啟老人機模式,放大字體!

普通-放大模式對比

這兩招一出,基本會給設計師和前端造成10000+傷害,不過我們仍然可以做點什么:

  • 嚴格控制頁面布局,字體超出部分截斷,保證頁面正常顯示;
  • 監(jiān)測頁面縮放情況并給予用戶提示;
  • 頁面自適應或者,針對老人模式單獨開發(fā)一套頁面。

小結

看到這里王二小已經殘血,稍微修整總結一下,字體表現不一致的根本原因有:

  • 排版引擎渲染策略差異(影響小,不可規(guī)避)
  • 各終端默認字體設置差異(影響中,可規(guī)避)
  • 用戶手動設置自定義字體(影響大,不可控)

目前為止我們能做的就是盡量使用Web 安全字體,針對不同終端對font-family字體選擇順序進行優(yōu)雅降級,并設置默認字體族來規(guī)避風險。

但只做到這些還遠遠不夠,我們完全處于被動狀態(tài),一切都依賴于終端環(huán)境的字體情況,并且還沒考慮到字體格式,中英混排,字體動畫,字體優(yōu)化,Web標準技術等方面。接下來我們要主動出擊,站在巨人的肩膀上去各個擊破,打怪升級,去尋找Web字體應用最佳實踐之道。

冒險越來越深入了,等待王二小的將會是什么呢?請看下集:

美麗新世界

參考資料

以下是相關參考資料,若想深入了解,建議仔細研讀。

Web 字體的選擇和運用

https://blog.coding.net/blog/Web-Fonts

網頁字體優(yōu)化

https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/webfont-optimization?hl=zh-cn

字體的各個概念術語

http://www.zhihu.com/question/20366900

字體渲染相關
Typekit Web字體渲染系列文章
網頁設計中默認字體詳解

https://waxdoll.gitbooks.io/webdesignfoundations/content/appendix/font_browser_default.html

Mac OS X 字體列表

https://en.wikipedia.org/wiki/List_of_typefaces_included_with_OS_X

Windows 字體列表
開源字體列表

https://en.wikipedia.org/wiki/Open-source_Unicode_typefaces

CSS Font Stack

http://www.cssfontstack.com/

數字設計之美

http://www.typeisbeautiful.com/2009/09/1467/

跨平臺字體效果淺析

https://isux.tencent.com/5058.html

對比 iOS 系統(tǒng) Android 的字體渲染有何區(qū)別

https://www.zhihu.com/question/21211748

iOS Font 字體整理
Mars/font-family

https://github.com/AlloyTeam/Mars/blob/master/solutions/font-family.md

網頁字體設置你了解嗎?

http://ued.ctrip.com/blog/web-page-font-settings-did-you-know.html

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現,斷路器,智...
    卡卡羅2017閱讀 136,545評論 19 139
  • 問答題47 /72 常見瀏覽器兼容性問題與解決方案? 參考答案 (1)瀏覽器兼容問題一:不同瀏覽器的標簽默認的外補...
    _Yfling閱讀 14,124評論 1 92
  • 發(fā)現 關注 消息 iOS 第三方庫、插件、知名博客總結 作者大灰狼的小綿羊哥哥關注 2017.06.26 09:4...
    肇東周閱讀 15,216評論 4 61
  • Swift版本點擊這里歡迎加入QQ群交流: 594119878最新更新日期:18-09-17 About A cu...
    ylgwhyh閱讀 26,028評論 7 249
  • 我出生在一個山村,這里依山傍水,我有好多個兄弟姐妹,從小到大,我們總在一起,我們從不爭吵,每天迎著朝霞,伴著日...
    納馬夸蘭閱讀 473評論 2 1

友情鏈接更多精彩內容