Web 字体应用指南最佳实践修炼之道(上)
據說把名字取得特別長更容易被搜索到。
故事的起源,要從UED界兩大種族前端設計師和視覺設計師的愛恨說起。
下面是設計師的視覺稿:
下面是前端開發出來的真實效果:
于是戰爭爆發了:
像這種視覺效果不一致問題,在日常開發中比比皆是。最近遇到的比較多的是字體問題,開了寫輪眼的設計師經常抱怨手機上的字體跟設計稿不一致,前端只能無奈的回一句手機上沒這字體啊...然而實際情況遠比這個復雜,正義的王二小見此情況決定挺身而出,踏上了Web字體修真之路,來尋找傳說中的最優解。
從0開始
這將是一次冒險,我們從0開始探索網頁中的文字是如何一步步呈現在我們眼前的。計算機的數據,本質上都是由01組成的序列,不同的序列可以傳達不同的信息,而同樣的序列通過不同的編碼和解碼方式也會傳達不同的信息。
我們所看到的網頁,都是從服務端網絡傳輸而來的一個個數據包通過瀏覽器解析而成,網絡傳輸其實是一個很復雜的編碼解碼過程,你可能聽過數據段,報文,分組,數據包,數據幀等關鍵詞,這些術語其實只是OSI模型中各個層對數據單位的不同劃分,最底層的表示還是以bit為單位的01。假設瀏覽器現在要渲染一段文本,它從服務端收到的數據包有一段信息是這樣的(當然為了簡化,除去報文頭等信息,假設下面這段信息就頁面上要展示的文本信息):
11100101 10001010 10101000 11100110 10000100 10011111 11100101 10110000 10001111 11100101 10001001 10001101 11100111 10101011 10101111這是一串字節流,瀏覽器得到它的第一件事自然是解碼,那么第一個問題,編碼方式很多種,瀏覽器怎么知道用哪種方式去解碼呢?
編碼與解碼
我們所熟知的編碼方式有ASCII,GB2321,UTF-8,UTF-16等等,對于瀏覽器來說,它會按照以下規則去尋找數據的編碼類型:
Web 服務器返回的 HTTP 頭中的 Content-Type: text/html; charset="xxx"。其中charset="xxx"就是編碼方式,當瀏覽器拿到這個信息之后,就能愉快的解碼了;
如果服務端沒有指定編碼方式,瀏覽器會去網頁文件的head中查找<meta charset="xxx">信息,來確定編碼方式;
如果還沒找到,那瀏覽器就只能自行判斷編碼了,或者讓用戶設置解碼方式。
可以看到,前兩步信息都是確定的,只有第三步是無法確定編碼方式的。所以為了讓你的頁面能正常展示出來,一定得要在前兩步就設定好charset編碼方式,以便于瀏覽器以你期望的方式解碼。
現代網頁通常都使用utf-8的編碼方式,所以我們就以此為例。utf-8是unicode字符集的一種實現方式,unicode本質上就是一個表,一個將二進制數據映射到各種文字符號的表,這個表野心很大,想要囊括世界上所有文字符號,并且他也實現了自己的目標,所以它也成了網絡世界應用最廣泛的一個表。
假設上面那串字節流采用了utf-8編碼,那么根據utf-8字節流到unicode的編碼規則:
可以看到上面那段字節流全都是1110xxxx 10xxxxxx 10xxxxxx的形式,那么根據表中第三行映射關系,應該是3個utf-8字節對應1個unicode編碼,將三個字節中的16個x用兩個字節表示,然后轉化成十六進制的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編碼在字體中匹配相應的輪廓,并最終渲染在屏幕上。通常我們都會給頁面指定一套字體規則:
font-family: Helvetica, STXihei, "Microsoft YaHei", Arial, SimSun,sans-serif;?瀏覽器會按照字體聲明的順序依次去尋找系統中已安裝的字體,如果找到了就按照該字體渲染,沒找到則依次往后查找,如果最后還是沒找到,則使用瀏覽器設置的神秘的默認字體。
渲染排版
確定了字體之后,瀏覽器就真的要去渲染了。如果你以為把字體設置的一樣就能萬事大吉了,那就太天真了。即使是相同的字體,不同的環境下渲染出來的結果也是不一樣的!就好比同樣是須佐能乎,不同人產生的形態也是不一樣的,先看兩張圖:
這是同一個頁面在不同環境下的顯示效果,其實如果在真實環境下看的話基本看不出來差別,但是對比一看差別還是很明顯的。MBP下是retina屏,顯示效果更細膩一些,而MBA下則更厚重些。放大來看,MBP下字體邊緣有灰色的邊緣(灰度渲染),而MBA下則是彩色的邊緣(次像素渲染)。
可以看到,同樣是Mac系統+Chrome瀏覽器,只是版本號稍微不同,渲染效果就會有所差別。更別說在Windows和Android上了。那么造成這種差異的原因是什么呢?
排版引擎
不同瀏覽器有著不同的渲染引擎,不同的操作系統上面也有不同的文字排版引擎,而瀏覽器在渲染頁面文本的時候都會調用系統的文字排版引擎。不同的排版策略就會造成不同的渲染結果。
Mac使用的排版引擎為CoreText,Windows7為DirectWrite/GDI,Windows XP則使用GDI。我們不會深入探索各個排版引擎的原理(想要深入了解Web字體渲染知識,可以去Typekit上了解更多),只需要知道不同的渲染引擎可能會造成字體有細節上的差異。即使是同一種渲染引擎,采用不同的渲染策略,比如灰度渲染和亞像素渲染,得出的效果也是不一樣的。
Core Text 渲染引擎:
DirectWrite渲染引擎:
GDI渲染引擎,開啟標準抗鋸齒:
GDI渲染引擎,無抗鋸齒:
由此可看出排版引擎渲染策略的差異是造成字體顯示效果不一致的根本原因之一,但是這種差異非常之小,對于普通用戶來說,根本不會注意到這些細節,所以前端工程師大可不必為此操心。
至此,我們終于走完文字從0渲染到屏幕上的整個過程。
諸子百家
之前有提到,當瀏覽器沒有找到所聲明的字體時,會使用默認字體。問題就在于,這個默認字體到底是什么字體呢?不同設備之間的默認字體又分別是什么?影響默認字體的因素又有哪些呢?
在舊PC時代,統治人類的主要是windows和mac兩大陣營,我們扳著手指頭都能列出各大平臺和瀏覽器上的默認字體。但是到了如今的無線亂世,安卓的開源讓每個設備廠商都可能會有自己獨特的默認字體,這對網頁的視覺統一性又帶來了巨大的挑戰。
裸奔字體
裸奔字體就是你的頁面不設置任何樣式,瀏覽器呈現出的默認字體,我寫了個小demo,你可以點擊試試看你瀏覽器上面的裸奔字體是啥,也可以掃碼看看手機上的情況:
在CrossBrowserTesting上跑了一下效果如下:
而在本人真機下的效果:
很明顯能看出,裸奔字體千變萬化,根本不靠譜!
安全字體
好在,現在已經沒有人裸奔了,一般都會在頁面中手動聲明一下字體,比如百度首頁是這樣的:
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;}上面四種寫法可能都有自己的考慮,但僅從終端字體表現的角度來看,很明顯淘寶的寫法更專業。Arial可謂是支持性最廣的字體了,所以大家都用上了,這種被大多數系統所默認支持的字體,就是Web安全字體。
CSS Font Stack上有對Web安全字體的整理,建議設計師們在作圖的時候多考慮一下,這樣能一定程度上降低視覺差異。并且某些字體其實長得還是蠻像的,你還可以使用安全字體來代替長相相似的非安全字體。
到目前為止,我們所做的一切考慮就是讓頁面字體效果在不同終端下盡可能保持一致,初步結論就是要使用安全字體,然而設計師并不這樣想。設計師一般會使用逼格比較高的非安全字體,比如蘭亭細黑,蘋方字體。一旦瀏覽器發現系統沒有這些字體,就會不斷降級,最壞的情況,就是一直降級到默認字體。所以通常我們會在font-family最后加上一個默認的字體族,比如sans-serif,這樣瀏覽器在最壞的情況下也能使用特定的字體族,并在該字體族下選擇一名指定字體來展示。
那么在這些指定的種族背后,被選中的孩子們到底都有誰呢?
神秘的默認字體
首先系統會默認安裝一些字體,維基上有對Win/Mac內置字體的整理:
Windows 字體列表
Mac OS X 字體列表
然后當你安裝軟件時,有可能會附帶安裝一些字體,這樣你系統上能支持的字體又變多了。在上面那份列表中,Win/Mac共同支持的字體只有Arial, Verdana, Tahoma, Trebuchet MS, Georgia等少數Web安全字體,對于Win/Mac平臺實際字體效果分析,請參考此文:
跨平臺字體效果淺析:https://isux.tencent.com/5058...
重點說下無線端, iOS Fonts 和iOS Font List網站整理了一份各個版本的iOS字體清單,可以很方便的查出各版本支持情況:
Helvetica字體完美支持:
蘋方字體從 iOS 9 才開始支持:
雖然方便,但畢竟第三方網站,不排除數據有誤的情況,于是附上官網聲明的字體清單:
iOS 5:字體列表
iOS 6:字體列表
iOS 7:字體列表
iOS 8:字體列表
iOS 9:字體列表
對于安卓,原生的安卓使用的是Droid Sans(英文/數字)和Droidsansfallback(中文),4.0后修改為Google的開源字體Roboto。而非原生安卓,實在沒有總結性可言。比如小米和華為用了方正蘭亭黑,錘子則使用了華文黑體,并且同一廠商下的不同手機品牌,同一品牌的不同型號默認字體都可能不同,不做展開。
一張圖總結一下(不是很完整,歡迎留言補充修正):
| iOS | Helvetica Neue | Heiti SC(黑體) | Tahoma / Arial / Verdana / georgia | STHeiti / 無宋體 / 無雅黑 |
| Android | Droid Sans(4.0以下) / Roboto(4.0以上) | Droid Sans Fallback(4.0以下) / Roboto(4.0) | Arial | 無雅黑,無宋體 |
| Mac OS X | Helvetica Neue | STHeiti華文黑體(10.6以下) / Hiragino Sans GB冬青黑體(10.6以上) | Tahoma / Arial / Verdana / georgia | 宋體 / 無雅黑 |
| Windows | 宋體 / segoe UI(Vista之后) | 宋體 / 微軟雅黑(Vista~8.1) / 微軟雅黑Light(8.1之后) | Tahoma / Arial / Verdana / Georgia | 微軟雅黑 / 黑體 |
| Windows Phone | Segoe | 雅黑(WP8以前) / 方正等線體(WP8之后) | - | - |
哦,忘了還有YunOS,貌似是方正蘭亭細黑...
強大的自定義字體
是的,用戶可以選擇自己喜歡的字體。你永遠不知道用戶會干什么,什么安全字體,默認字體,一個主題包下來全都是浮云:
用戶修改系統字體:
當然這不是最絕的,換個字體最多樣子變了,最絕的是用戶開啟老人機模式,放大字體!
普通-放大模式對比:
這兩招一出,基本會給設計師和前端造成10000+傷害,不過我們仍然可以做點什么:
嚴格控制頁面布局,字體超出部分截斷,保證頁面正常顯示;
監測頁面縮放情況并給予用戶提示;
頁面自適應或者,針對老人模式單獨開發一套頁面。
小結
看到這里王二小已經殘血,稍微修整總結一下,字體表現不一致的根本原因有:
排版引擎渲染策略差異(影響小,不可規避)
各終端默認字體設置差異(影響中,可規避)
用戶手動設置自定義字體(影響大,不可控)
目前為止我們能做的就是盡量使用Web 安全字體,針對不同終端對font-family字體選擇順序進行優雅降級,并設置默認字體族來規避風險。
但只做到這些還遠遠不夠,我們完全處于被動狀態,一切都依賴于終端環境的字體情況,并且還沒考慮到字體格式,中英混排,字體動畫,字體優化,Web標準技術等方面。接下來我們要主動出擊,站在巨人的肩膀上去各個擊破,打怪升級,去尋找Web字體應用最佳實踐之道。
冒險越來越深入了,等待王二小的將會是什么呢?請看下集:
參考資料
以下是相關參考資料,若想深入了解,建議仔細研讀。
Web 字體的選擇和運用
https://blog.coding.net/blog/...
網頁字體優化
https://developers.google.com...
字體的各個概念術語
http://www.zhihu.com/question...?
字體渲染相關
http://ued.ctrip.com/blog/fon...
http://blog.jobbole.com/21671/
http://isux.tencent.com/websi...
https://developer.apple.com/f...
Typekit Web字體渲染系列文章
http://blog.typekit.com/2010/...
http://blog.typekit.com/2010/...
http://blog.typekit.com/2010/...
http://blog.typekit.com/2010/...
http://blog.typekit.com/2010/...
http://blog.typekit.com/2010/...
http://blog.typekit.com/2010/...
網頁設計中默認字體詳解
https://waxdoll.gitbooks.io/w...
Mac OS X 字體列表
https://en.wikipedia.org/wiki...
Windows 字體列表
https://en.wikipedia.org/wiki...
http://www.microsoft.com/typo...
開源字體列表
https://en.wikipedia.org/wiki...
CSS Font Stack
http://www.cssfontstack.com/
數字設計之美
http://www.typeisbeautiful.co...
跨平臺字體效果淺析
https://isux.tencent.com/5058...
對比 iOS 系統 Android 的字體渲染有何區別
https://www.zhihu.com/questio...
iOS Font 字體整理
http://iosfonts.com/
http://iosfontlist.com/
Mars/font-family
https://github.com/AlloyTeam/...
網頁字體設置你了解嗎?
http://ued.ctrip.com/blog/web...
總結
以上是生活随笔為你收集整理的Web 字体应用指南最佳实践修炼之道(上)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 银行用计算机实现了,银行考试计算机专项练
- 下一篇: Element UI组件介绍