故事的起源,要從UED界兩大種族前端設(shè)計師和視覺設(shè)計師的愛恨說起:
像這種視覺效果不一致問題梗醇,在日常開發(fā)中比比皆是词身。最近遇到的比較多的是字體問題练湿,開了寫輪眼的設(shè)計師經(jīng)常抱怨手機上的字體跟設(shè)計稿不一致,前端只能無奈的回一句手機上沒這字體啊...然而實際情況遠比這個復(fù)雜涌庭,正義的王二小見此情況決定挺身而出芥被,踏上了Web字體修真之路,來尋找傳說中的最優(yōu)解坐榆。
從0開始
這將是一次冒險拴魄,我們從0開始探索網(wǎng)頁中的文字是如何一步步呈現(xiàn)在我們眼前的。計算機的數(shù)據(jù)席镀,本質(zhì)上都是由01組成的序列匹中,不同的序列可以傳達不同的信息,而同樣的序列通過不同的編碼和解碼方式也會傳達不同的信息豪诲。
我們所看到的網(wǎng)頁顶捷,都是從服務(wù)端網(wǎng)絡(luò)傳輸而來的一個個數(shù)據(jù)包通過瀏覽器解析而成,網(wǎng)絡(luò)傳輸其實是一個很復(fù)雜的編碼解碼過程屎篱,你可能聽過數(shù)據(jù)段服赎,報文,分組交播,數(shù)據(jù)包重虑,數(shù)據(jù)幀等關(guān)鍵詞,這些術(shù)語其實只是OSI模型中各個層對數(shù)據(jù)單位的不同劃分堪侯,最底層的表示還是以bit為單位的01嚎尤。假設(shè)瀏覽器現(xiàn)在要渲染一段文本,它從服務(wù)端收到的數(shù)據(jù)包有一段信息是這樣的(當(dāng)然為了簡化伍宦,除去報文頭等信息芽死,假設(shè)下面這段信息就頁面上要展示的文本信息):
11100101 10001010 10101000
11100110 10000100 10011111
11100101 10110000 10001111
11100101 10001001 10001101
11100111 10101011 10101111
這是一串字節(jié)流乏梁,瀏覽器得到它的第一件事自然是解碼,那么第一個問題关贵,編碼方式很多種遇骑,瀏覽器怎么知道用哪種方式去解碼呢?
編碼與解碼
我們所熟知的編碼方式有ASCII揖曾,GB2321落萎,UTF-8,UTF-16等等炭剪,對于瀏覽器來說练链,它會按照以下規(guī)則去尋找數(shù)據(jù)的編碼類型:
- Web 服務(wù)器返回的 HTTP 頭中的 Content-Type: text/html; charset="xxx"。其中charset="xxx"就是編碼方式,當(dāng)瀏覽器拿到這個信息之后奴拦,就能愉快的解碼了媒鼓;
- 如果服務(wù)端沒有指定編碼方式,瀏覽器會去網(wǎng)頁文件的head中查找<meta charset="xxx">信息错妖,來確定編碼方式绿鸣。
- 如果還沒找到,那瀏覽器就只能自行判斷編碼了暂氯,或者讓用戶設(shè)置解碼方式潮模。
可以看到,前兩步信息都是確定的痴施,只有第三步是無法確定編碼方式的擎厢。所以為了讓你的頁面能正常展示出來,一定得要在前兩步就設(shè)定好charset編碼方式晾剖,以便于瀏覽器以你期望的方式解碼锉矢。
現(xiàn)代網(wǎng)頁通常都使用utf-8的編碼方式,所以我們就以此為例齿尽。utf-8是unicode字符集的一種實現(xiàn)方式沽损,unicode本質(zhì)上就是一個表,一個將二進制數(shù)據(jù)映射到各種文字符號的表循头,這個表野心很大绵估,想要囊括世界上所有文字符號,并且他也實現(xiàn)了自己的目標(biāo)卡骂,所以它也成了網(wǎng)絡(luò)世界應(yīng)用最廣泛的一個表国裳。
假設(shè)上面那串字節(jié)流采用了utf-8編碼,那么根據(jù)utf-8字節(jié)流到unicode的編碼規(guī)則:
可以看到上面那段字節(jié)流全都是1110xxxx 10xxxxxx 10xxxxxx的形式,那么根據(jù)表中第三行映射關(guān)系全跨,應(yīng)該是3個utf-8字節(jié)對應(yīng)1個unicode編碼缝左,將三個字節(jié)中的16個x用兩個字節(jié)表示,然后轉(zhuǎn)化成十六進制的unicode表示,最終可得到以下結(jié)果:
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編碼之后渺杉,我們就可以根據(jù)unicode字符表找到對應(yīng)的文字符號蛇数,最終得到了以下結(jié)果:
\u52a8\u611f\u5c0f\u524d\u7aef -> 動感小前端
如果對最終的結(jié)果不確定,可以反向驗證一下:
escape('動感小前端') // "%u52A8%u611F%u5C0F%u524D%u7AEF"
得出的unicode字符數(shù)值完全一致是越,看來計算沒錯耳舅,那么緊接著第二個問題來了,瀏覽器該如何去展示它倚评?就好比我知道你的名字叫什么浦徊,但并不知道怎么寫一樣。
尋找字體
字體的渲染是一個很復(fù)雜的過程天梧,首先我們需要知道在Web世界中存在著五大字體家族盔性,江湖人稱font-family:serif、sans-serif腿倚、monospace纯出、cursive和fantasy蚯妇。在這五大家族下面敷燎,又演變出各個不同的字體,比如宋體箩言,微軟雅黑硬贯,Arial,Helvetica等等陨收。同樣的文字饭豹,在不同的字體下面會呈現(xiàn)出不同的效果:
但是,不管是什么字體务漩,他們本質(zhì)上都是一個表拄衰。你可以把這個表理解成三個部分:
- 輪廓:用來記載字符的形狀;
- 編碼:用來記載字符內(nèi)部編號與字符形狀以及unicode編碼之間的映射關(guān)系饵骨;
- 封裝:將上面這些東西封裝成特定的文件格式
想要深入了解字體內(nèi)部原理翘悉,請走支線劇情《Fonts & Encodings》
瀏覽器在渲染字體時,首先會把這些文字分為不同語言的小段居触,然后依次確定該用哪一種字體妖混,確定之后按照字符的unicode編碼在字體中匹配相應(yīng)的輪廓,并最終渲染在屏幕上轮洋。通常我們都會給頁面指定一套字體規(guī)則:
font-family: Helvetica, STXihei, "Microsoft YaHei", Arial, SimSun,sans-serif;
瀏覽器會按照字體聲明的順序依次去尋找系統(tǒng)中已安裝的字體制市,如果找到了就按照該字體渲染,沒找到則依次往后查找弊予,如果最后還是沒找到祥楣,則使用瀏覽器設(shè)置的神秘的默認(rèn)字體。
渲染排版
確定了字體之后,瀏覽器就真的要去渲染了误褪。如果你以為把字體設(shè)置的一樣就能萬事大吉了床未,那就太天真了。即使是相同的字體振坚,不同的環(huán)境下渲染出來的結(jié)果也是不一樣的薇搁!就好比同樣是須佐能乎,不同人產(chǎn)生的形態(tài)也是不一樣的,先看兩張圖:
這是同一個頁面在不同環(huán)境下的顯示效果渡八,其實如果在真實環(huán)境下看的話基本看不出來差別啃洋,但是對比一看差別還是很明顯的。MBP下是retina屏屎鳍,顯示效果更細膩一些宏娄,而MBA下則更厚重些。放大來看逮壁,MBP下字體邊緣有灰色的邊緣(灰度渲染)孵坚,而MBA下則是彩色的邊緣(次像素渲染)。
可以看到窥淆,同樣是Mac系統(tǒng)+Chrome瀏覽器卖宠,只是版本號稍微不同,渲染效果就會有所差別忧饭。更別說在Windows和Android上了扛伍。那么造成這種差異的原因是什么呢?
排版引擎
不同瀏覽器有著不同的渲染引擎词裤,不同的操作系統(tǒng)上面也有不同的文字排版引擎刺洒,而瀏覽器在渲染頁面文本的時候都會調(diào)用系統(tǒng)的文字排版引擎。不同的排版策略就會造成不同的渲染結(jié)果吼砂。
Mac使用的排版引擎為CoreText逆航,Windows7為DirectWrite/GDI,Windows XP則使用GDI。我們不會深入探索各個排版引擎的原理(想要深入了解Web字體渲染知識渔肩,可以去Typekit上了解更多)因俐,只需要知道不同的渲染引擎可能會造成字體有細節(jié)上的差異。即使是同一種渲染引擎赖瞒,采用不同的渲染策略女揭,比如灰度渲染和亞像素渲染,得出的效果也是不一樣的栏饮。
由此可看出排版引擎渲染策略的差異是造成字體顯示效果不一致的根本原因之一袍嬉,但是這種差異非常之小境蔼,對于普通用戶來說灶平,根本不會注意到這些細節(jié),所以前端工程師大可不必為此操心箍土。
至此逢享,我們終于走完文字從0渲染到屏幕上的整個過程。
諸子百家
之前有提到吴藻,當(dāng)瀏覽器沒有找到所聲明的字體時瞒爬,會使用默認(rèn)字體。問題就在于沟堡,這個默認(rèn)字體到底是什么字體呢侧但?不同設(shè)備之間的默認(rèn)字體又分別是什么?影響默認(rèn)字體的因素又有哪些呢航罗?
在舊PC時代禀横,統(tǒng)治人類的主要是windows和mac兩大陣營,我們扳著手指頭都能列出各大平臺和瀏覽器上的默認(rèn)字體粥血。但是到了如今的無線亂世柏锄,安卓的開源讓每個設(shè)備廠商都可能會有自己獨特的默認(rèn)字體,這對網(wǎng)頁的視覺統(tǒng)一性又帶來了巨大的挑戰(zhàn)复亏。
裸奔字體
裸奔字體就是你的頁面不設(shè)置任何樣式趾娃,瀏覽器呈現(xiàn)出的默認(rèn)字體,我寫了個小demo蜓耻,你可以點擊試試看你瀏覽器上面的裸奔字體是啥茫舶,也可以掃碼看看手機上的情況:
在CrossBrowserTesting上跑了一下效果如下:
而在本人真機下的效果:
很明顯能看出,裸奔字體千變?nèi)f化刹淌,根本不靠譜!
安全字體
好在讥耗,現(xiàn)在已經(jīng)沒有人裸奔了有勾,一般都會在頁面中手動聲明一下字體,比如百度首頁是這樣的:
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;}
上面四種寫法可能都有自己的考慮古程,但僅從終端字體表現(xiàn)的角度來看蔼卡,很明顯淘寶的寫法更專業(yè)。Arial可謂是支持性最廣的字體了挣磨,所以大家都用上了雇逞,這種被大多數(shù)系統(tǒng)所默認(rèn)支持的字體,就是Web安全字體茁裙。
CSS Font Stack上有對Web安全字體的整理塘砸,建議設(shè)計師們在作圖的時候多考慮一下,這樣能一定程度上降低視覺差異晤锥。并且某些字體其實長得還是蠻像的掉蔬,你還可以使用安全字體來代替長相相似的非安全字體廊宪。
到目前為止女轿,我們所做的一切考慮就是讓頁面字體效果在不同終端下盡可能保持一致箭启,初步結(jié)論就是要使用安全字體,然而設(shè)計師并不這樣想蛉迹。設(shè)計師一般會使用逼格比較高的非安全字體傅寡,比如蘭亭細黑,蘋方字體。一旦瀏覽器發(fā)現(xiàn)系統(tǒng)沒有這些字體北救,就會不斷降級赏僧,最壞的情況,就是一直降級到默認(rèn)字體扭倾。所以通常我們會在font-family最后加上一個默認(rèn)的字體族淀零,比如sans-serif,這樣瀏覽器在最壞的情況下也能使用特定的字體族膛壹,并在該字體族下選擇一名指定字體來展示驾中。
那么在這些指定的種族背后,被選中的孩子們到底都有誰呢模聋?
神秘的默認(rèn)字體
首先系統(tǒng)會默認(rèn)安裝一些字體肩民,維基上有對Win/Mac內(nèi)置字體的整理:
然后當(dāng)你安裝軟件時,有可能會附帶安裝一些字體链方,這樣你系統(tǒng)上能支持的字體又變多了持痰。在上面那份列表中,Win/Mac共同支持的字體只有Arial, Verdana, Tahoma, Trebuchet MS, Georgia等少數(shù)Web安全字體祟蚀,對于Win/Mac平臺實際字體效果分析工窍,請參考此文:
跨平臺字體效果淺析:https://isux.tencent.com/5058.html
重點說下無線端, iOS Fonts 和iOS Font List網(wǎng)站整理了一份各個版本的iOS字體清單,可以很方便的查出各版本支持情況:
雖然方便前酿,但畢竟第三方網(wǎng)站患雏,不排除數(shù)據(jù)有誤的情況,于是附上官網(wǎng)聲明的字體清單:
對于安卓罢维,原生的安卓使用的是Droid Sans(英文/數(shù)字)和Droidsansfallback(中文),4.0后修改為Google的開源字體Roboto淹仑。而非原生安卓,實在沒有總結(jié)性可言肺孵。比如小米和華為用了方正蘭亭黑匀借,錘子則使用了華文黑體,并且同一廠商下的不同手機品牌平窘,同一品牌的不同型號默認(rèn)字體都可能不同吓肋,不做展開。
一張圖總結(jié)一下:
哦初婆,忘了還有Windows Phone蓬坡,WP默認(rèn)英文字體是Segoe猿棉,中文字體在WP8以前是雅黑,WP8之后是方正等線體屑咳。
哦萨赁,忘了還有YunOS,貌似是方正蘭亭細黑...
強大的自定義字體
是的兆龙,用戶可以選擇自己喜歡的字體杖爽。你永遠不知道用戶會干什么,什么安全字體紫皇,默認(rèn)字體慰安,一個主題包下來全都是浮云:
當(dāng)然這不是最絕的,換個字體最多樣子變了聪铺,最絕的是用戶開啟老人機模式化焕,放大字體!
這兩招一出铃剔,基本會給設(shè)計師和前端造成10000+傷害撒桨,不過我們?nèi)匀豢梢宰鳇c什么:
- 嚴(yán)格控制頁面布局,字體超出部分截斷键兜,保證頁面正常顯示凤类;
- 監(jiān)測頁面縮放情況并給予用戶提示;
- 頁面自適應(yīng)或者普气,針對老人模式單獨開發(fā)一套頁面谜疤。
小結(jié)
看到這里王二小已經(jīng)殘血,稍微修整總結(jié)一下现诀,字體表現(xiàn)不一致的根本原因有:
- 排版引擎渲染策略差異(影響小夷磕,不可規(guī)避)
- 各終端默認(rèn)字體設(shè)置差異(影響中,可規(guī)避)
- 用戶手動設(shè)置自定義字體(影響大赶盔,不可控)
目前為止我們能做的就是盡量使用Web 安全字體企锌,針對不同終端對font-family字體選擇順序進行優(yōu)雅降級,并設(shè)置默認(rèn)字體族來規(guī)避風(fēng)險于未。
但只做到這些還遠遠不夠,我們完全處于被動狀態(tài)陡鹃,一切都依賴于終端環(huán)境的字體情況烘浦,并且還沒考慮到字體格式,中英混排萍鲸,字體動畫闷叉,字體優(yōu)化,Web標(biāo)準(zhǔn)技術(shù)等方面脊阴。接下來我們要主動出擊握侧,站在巨人的肩膀上去各個擊破蚯瞧,打怪升級,去尋找Web字體應(yīng)用最佳實踐之道品擎。
冒險越來越深入了埋合,等待王二小的將會是什么呢?請看下集:
參考資料
以下是相關(guān)參考資料萄传,若想深入了解甚颂,建議仔細研讀。
Web 字體的選擇和運用
https://blog.coding.net/blog/Web-Fonts
網(wǎng)頁字體優(yōu)化
字體的各個概念術(shù)語
http://www.zhihu.com/question/20366900
字體渲染相關(guān)
- http://ued.ctrip.com/blog/font-rendering.html
- http://blog.jobbole.com/21671/
- http://isux.tencent.com/website-font-rendering-process.html
- https://developer.apple.com/fonts/TrueType-Reference-Manual/RM02/Chap2.html
Typekit Web字體渲染系列文章
- http://blog.typekit.com/2010/10/05/type-rendering-on-the-web/
- http://blog.typekit.com/2010/10/15/type-rendering-operating-systems/
- http://blog.typekit.com/2010/10/21/type-rendering-web-browsers/
- http://blog.typekit.com/2010/11/09/type-rendering-the-design-of-fonts-for-the-web/
- http://blog.typekit.com/2010/12/08/type-rendering-font-outlines-and-file-formats/
- http://blog.typekit.com/2010/12/14/a-closer-look-at-truetype-hinting/
- http://blog.typekit.com/2010/12/17/type-rendering-review-and-fonts-that-render-well/
網(wǎng)頁設(shè)計中默認(rèn)字體詳解
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/List_of_typefaces_included_with_Microsoft_Windows
- http://www.microsoft.com/typography/fonts/product.aspx
開源字體列表
https://en.wikipedia.org/wiki/Open-source_Unicode_typefaces
CSS Font Stack
數(shù)字設(shè)計之美
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
網(wǎng)頁字體設(shè)置你了解嗎秀菱?
http://ued.ctrip.com/blog/web-page-font-settings-did-you-know.html