聽說把名字取得特別長更容易被搜索到。javascript
故事的起源,要從UED界兩大種族前端設計師和視覺設計師的愛恨提及。css
下面是設計師的視覺稿:html
下面是前端開發出來的真實效果:前端
因而戰爭爆發了:java
像這種視覺效果不一致問題,在平常開發中比比皆是。最近遇到的比較多的是字體問題,開了寫輪眼的設計師常常抱怨手機上的字體跟設計稿不一致,前端只能無奈的回一句手機上沒這字體啊...然而實際狀況遠比這個複雜,正義的王二小見此狀況決定自告奮勇,踏上了Web字體修真之路,來尋找傳說中的最優解。ios
這將是一次冒險,咱們從0開始探索網頁中的文字是如何一步步呈如今咱們眼前的。計算機的數據,本質上都是由01組成的序列,不一樣的序列能夠傳達不一樣的信息,而一樣的序列經過不一樣的編碼和解碼方式也會傳達不一樣的信息。git
咱們所看到的網頁,都是從服務端網絡傳輸而來的一個個數據包經過瀏覽器解析而成,網絡傳輸實際上是一個很複雜的編碼解碼過程,你可能聽過數據段,報文,分組,數據包,數據幀等關鍵詞,這些術語其實只是OSI模型中各個層對數據單位的不一樣劃分,最底層的表示仍是以bit爲單位的01。假設瀏覽器如今要渲染一段文本,它從服務端收到的數據包有一段信息是這樣的(固然爲了簡化,除去報文頭等信息,假設下面這段信息就頁面上要展現的文本信息):github
11100101 10001010 10101000 11100110 10000100 10011111 11100101 10110000 10001111 11100101 10001001 10001101 11100111 10101011 10101111
這是一串字節流,瀏覽器獲得它的第一件事天然是解碼,那麼第一個問題,編碼方式不少種,瀏覽器怎麼知道用哪一種方式去解碼呢?web
咱們所熟知的編碼方式有ASCII,GB2321,UTF-8,UTF-16等等,對於瀏覽器來講,它會按照如下規則去尋找數據的編碼類型:windows
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內置字體的整理:
而後當你安裝軟件時,有可能會附帶安裝一些字體,這樣你係統上能支持的字體又變多了。在上面那份列表中,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 纔開始支持:
雖然方便,但畢竟第三方網站,不排除數據有誤的狀況,因而附上官網聲明的字體清單:
對於安卓,原生的安卓使用的是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字體應用最佳實踐之道。
冒險愈來愈深刻了,等待王二小的將會是什麼呢?請看下集:
如下是相關參考資料,若想深刻了解,建議仔細研讀。
https://blog.coding.net/blog/...
https://developers.google.com...
http://www.zhihu.com/question...
https://waxdoll.gitbooks.io/w...
https://en.wikipedia.org/wiki...
https://en.wikipedia.org/wiki...
http://www.typeisbeautiful.co...
https://isux.tencent.com/5058...
https://www.zhihu.com/questio...
https://github.com/AlloyTeam/...