隨着網頁個性化設計和品牌特色的需要,在網頁中使用特定的字體將成為越來越常見的需求。現代字體設計經歷了數十年的發展,已經積累了成熟的標準和規範,但對於許多前端開發者來説可能可能還比較陌生,本文就前端開發過程中可能遇到的字體知識做一個梳理和介紹。
博客原文:https://www.hozen.site/archives/64/
字體基礎
字體標準
字體的設計和使用和其他任何工業設計產品一樣,需要統一的標準和規範。
最初的計算機字體是點陣字體,放大後會有明顯的馬賽克。為了高清打印和縮放的需求,Adobe 公司於 1984 年發佈了 PostScript 語言,使用三次貝塞爾曲線來繪製字體,極大的提高了字體打印和屏幕顯示質量[1]。很快蘋果又推出了 TrueType 字體標準,採用二次貝塞爾曲線繪製字體,被廣泛應用於 macOS 和 Windows 系統中[2]。
1996 年微軟聯合 Adobe 在 TrueType 的基礎上推出了 OpenType 字體標準,該標準整合了 PostScript 字體和 TrueType 字體的特點,並新增了許多新的特性。OpenType 陸續得到蘋果和谷歌等公司的支持,在主流計算機平台應用廣泛,目前已經成為字體設計的主要發展趨勢[3]。
總的來説,字體(輪廓字體 Outline fonts)標準整體上有 3 種,但對於普通用户和開發者來説 TrueType 和 Opentype 比較常見。
字體文件
字體設計完成後將打包成特定文件分發給用户,字體文件根據標準的不同採用不同的後綴名。TrueType 字體以 .ttf 作為後綴名。OpenType 字體根據不同的情況採用 .otf, .ttf, .otc 和 .ttc 為後綴,其中 OTF 一般表示基於 PostScript 技術,對應地,TTF 表示使用 TrueType 技術。而 OTC 和 TTC 則表示字體集合(Collection),即一個文件中包含多種字體(例如多種語言)[4]。這 4 種字體文件在主流操作系統和網頁設計中都是可用的。
除此之外,還有專用於網頁的網頁開放字體(Web Open Font Format)格式,其設計標準通常為 OpenType 或 TureType,但在文件打包和壓縮中專門為網絡傳輸做了優化。WOFF 字體在主流瀏覽器中都得到很好的支持,文件後綴名為 .woff 以及 .woff2。
字體類型
常見的字體可以分為“襯線(serif)”、“無襯線(sans serif)”、“等寬(monospace)”等類型。襯線是指在字體筆畫末端有小裝飾。在論文寫作中常用的 Times New Roman 字體和中文宋體便是襯線字體。無襯線字體的字體線條則相對簡約,例如 Arial 和“微軟雅黑”以及“蘋方”。等寬字體則表示每個字符佔據相等的寬度,這一點襯線和無襯線字體是無法保證的,例如小寫字母 i 在非等寬字體中往往佔據較小的字寬。
由於襯線字體具有更豐富的細節且更加精緻,所以多用於印刷和高清顯示。無襯線字體在屏幕顯示上更加普遍,主流瀏覽器和操作系統的默認字體一般都是無襯線字體。但隨着屏幕分辨率的提高和顯示技術的提升,在屏幕顯示中使用襯線字體可以使文本頁面更加精緻具備設計感。例如我的主頁首頁部分字體就使用了思源宋體。等寬字體由於具備字符等寬的特點往往被用於代碼的編輯和顯示。
字體家族 Font Family
前文提到的諸如“Times New Roman“,“微軟雅黑”等字體其實都是字體家族的概念。字體家族代表了統一的設計風格,但字體往往需要不同的粗細(字重)和樣式(斜體、字寬等)。因此一個字體家族可以包含不同的子字體來實現不同的字體樣式。具體地,字體樣式包括字重、字寬、傾斜和視覺尺寸等方面,通過這些樣式的組合便產生不同的子字體。但除非特別需要,對於屏幕顯示來説常用的子字體樣式一般只包括字重和傾斜。例如,蘋方字體家族字體包括常規體(Regular)、極細體(Ultralight)、纖細體(Thin)、細體(Light)、中黑體(Medium)和中粗體(Semibold)6 個子字體。當然也有一些發佈較早的字體只包含一種樣式,即一個字體文件。
當我們使用文字處理軟件或者 CSS 屬性對字體應用“加粗”和“傾斜”等樣式時,系統會查找對應樣式的子字體是否可用,如果可用則使用對應的子字體,否則則通過計算對字體進行強制的加粗和傾斜。雖然這兩種方式最終都將字體進行了加粗或傾斜,但效果是完全不一樣的。子字體不同的樣式通過了嚴格的設計,使其具備統一的美感。而後者只是簡單粗暴的加粗或傾斜,視覺效果往往比不上前者。例如,下圖中分別使用思源宋體的常規體進行計算加粗(上)和直接使用思源宋體的 Bold 字體(下),可以明顯看出上面的文字在細節和觀感上相去甚遠。
可變字體(Variable Font)
一款優秀的字體會提供多種字重的子字體,這樣能保證在使用不同字重時能夠保持優秀的觀感。但每一款單獨的字重或樣式的字體往往需要單獨的字體文件,這導致了當字體樣式變多時字體文件數量增加,尤其對於網絡頁面來説會增加請求次數和流量負擔。
為了解決這一問題,在 OpenType 規範的中,Adobe、微軟、蘋果和谷歌於 2016 年共同推出了可變字體(Variable font)的標準,這一標準改變了字體樣式的設計和使[5]]。就字重來説,不再需要多個字重的字體文件,一個字體文件即可使用多種字重。並且,字體字重不再被離散的劃分為“常規”,“中黑”等有限的個數,而是能夠通過調整字重參數獲得任意粗細,實現字重的無級調節。像下圖中 MIUI 的動態交互效果在沒有可變字體時是很難實現的。
OpenType 要求可變字體文件需要在命名使用 VF標註,例如 Selawik-VF.ttf。因此我們從字體文件名往往可以分辨該字體是否是可變字體。
CSS 屬性
默認字體名稱
CSS 屬性 font-family 用於指定字體,並且規定了 5 種默認的字體名稱:serif, sans-serif, monospace, cursive, fantasy,除了前面提到的 3 種字體,cursive 和 fantasy 分別表示手寫字體和裝飾字體。當使用這些默認字體名稱時,具體使用何種字體是由瀏覽器決定的,往往也會根據操作系統的不用有所不同。
雖然使用默認的字體屬性可能會造成跨平台字體表現不一致的情況,但對於大多數功能性網頁來説不必過分擔心,因為在主流平台中字體經過了嚴格設計,規範性和易用性是完全經得住考驗的。
字體棧
使用 font-family 除了上述 5 種默認字體名稱外,可以指定具體的字體名稱,例如 Times New Roman。當指定的字體不可用(系統未安裝該字體或遠程字體加載失敗)時則會使用瀏覽器默認字體。
為了防止字體退化為默認字體,可以為 font-family 指定多個字體,例如 font-family: "Times New Roman", Times, serif。瀏覽器會按照屬性列出的先後順序查找和使用字體,直到找到第一個可用的字體,當字體都不可用時則使用瀏覽器默認的字體。
在字體棧的最後使用一個默認字體名稱是不錯的選擇,因為即使瀏覽器沒有找到合適的字體也會使用一個還算合適的字體。否則,當所有字體都不可用時,為了強調這一點,相應文字將被賦予瀏覽器的默認襯線字體 - 通常是 Time New Roman - 這對於 sans-serif 字體是不利的!
網絡安全字體
前文提到,在不同的瀏覽器和操作系統中網頁的默認字體會有所不同。當對頁面有跨平台時保持字體統一的要求時,可以使用“網絡安全字體“,安全字體即挑選出在主流平台都默認安裝的字體,來保證跨平台時字體的可用性。
以下是拉丁文字體的網絡安全字體:
| 字體名稱 | 泛型 | 注意 |
|---|---|---|
| Arial | sans-serif | 使用 Helvetica 作為 Arial 首選替代 |
| Georgia | serif | |
| Times New Roman | serif | 使用 Times 作為 Times New Roman 的首選替代方案 |
| Courier New | monospace | 使用 Courier 作為 Courier New 的首選替代方案 |
| Trebuchet MS | sans-serif | 應該小心使用這種字體——它在移動操作系統上並不廣泛 |
| Verdana | sans-serif |
其中“首選替代方案”往往是因為同一款字體的不同版本在新舊操作系統上安裝情況或名稱不一致,使用字體棧包含各種可能的名稱來保證可用性。
CSS 自定義字體
CSS3 引入 @font-face 規則,可以從遠程服務器加載字體文件或使用户本安裝的字體。這一特性使得網頁設計不必侷限於默認字體或“網絡安全字體”,使得網頁設計更具個性和品牌表達力。
一個使用 @font-face 的加載遠程字體的典型例子:
<html>
<head>
<title>Web Font Sample</title>
<style type="text/css" media="screen, print">
@font-face {
font-family: "Bitstream Vera Serif Bold";
src: url("https://mdn.github.io/css-examples/web-fonts/VeraSeBd.ttf");
}
body { font-family: "Bitstream Vera Serif Bold", serif }
</style>
</head>
<body>
This is Bitstream Vera Serif Bold.
</body>
</html>
但是,請注意!上面例子中的文字將以“Times New Roman”字體展示,這是因為 @font-face 的遠程字體文件加載同樣需要遵循同源策略,我們在加載 github.io 的跨域資源將加載失敗。還記得前文提到,當字體棧不可用時會使用瀏覽器的默認襯線字體作為提醒嗎?這就是為什麼上例的文字最終會以“Times New Roman”字體展示。
@font-face 常用的屬性有:
font-family,指定字體的名字,將會被用於 font 或 font-family 屬性src,遠程字體文件位置的 URL 或者用户計算機上的字體名稱,可以使用local語法通過名稱指定用户的本地計算機上的字體 ( i.e.src: local('Arial');)。如果找不到該字體,將會嘗試其他來源,直到找到它。font-weight,定義該字體的字重,如果所需字體符合描述,則採用本 font-face 所定義的字體。font-style,定義該字體的樣式。如果所需字體符合描述,則採用本 font-face 所定義的字體。
除此之外還有 font-variant,font-stretch 和 unicode-range 等屬性,可以參照 @font-face - CSS:層疊樣式表 | MDN。
@font-face 定義多字重字體
上文提到,雖然瀏覽器可以對常規字體進行強制加粗但視覺效果並不理想,但不同的樣式又對應不同的字體文件,如何使用 @font-face 加載不同樣式的子字體文件呢?答案是通過定義不同的字體樣式來加載不用的字體文件,例如:
<html>
<head>
<style>
@font-face {
font-family: 'Source Han Serif';
src: url(/font/SourceHanSerifCN/regular.ttf);
}
@font-face {
font-family: 'Source Han Serif'; /* 同一個字體名稱 */
src: url(/font/SourceHanSerifCN/bold.ttf); /* 但不同的字體文件 */
font-weight: bold; /* 根據字重應用不同的文件 */
}
.regular{
font-family: "Source Han Serif";
font-size: 30px;
/* 常規字體,應用 regular.ttf 字體文件 */
}
.bold {
font-family: "Source Han Serif";
font-size: 30px;
font-weight: bold;
/* 加粗字體,應用 bold.ttf 字體文件 */
}
</style>
</head>
<body>
<div class="regular">海內存知己,天涯若比鄰。</div>
<div class="bold">海內存知己,天涯若比鄰。</div>
</body>
</html>
顯示效果如下:
類似地,還可以為斜體等字體效果單獨指定字體文件。
如果你使用的字體有可變字體版本,那麼只需要加載一個字體文件就可以把全部樣式搞定了!
字體提取壓縮
對於拉丁文語言來説,一個完整的字體文件通常不過幾百 KB,因為只需要很少的一些字符就能完整地表達所有單詞和句子。但對於漢字這種象形文字來説,每一個字符都需要單獨的設計,因此完整的漢字字體包往往達到數十兆大小。這對於網絡頁面加載來説是十分不利的。
因此,在頁面設計中如無必要往往不會對漢字正文字體使用自定義的遠程字體。但在有些時候,我們為了頁面設計的美觀和各種文本的區分,可能需要對主頁標題或重要信息使用特定設計的字體。在這種情況下,使用特殊字體的字符數往往很少,如果因此就引入一個數十兆的字體文件顯然得不償失。
應對這種情況,使用切圖可能是一種解決方案。但切圖不利於 SEO,且當字體內容頻繁更新時需要依賴設計人員,十分不便。此時,可以考慮使用自動化的腳本將頁面中使用到特殊字體的字符進行提取,然後重新壓縮成一個只包含特定字符的字體包來取代完整的字體包,這將大大提高頁面加載速度。
頁面字體提取和壓縮已經有一些第三方庫可用,例如 font-snake、fontmin 和 font-spider 等。除此之外還有專門針對字體設計的 opentype.js,該庫保持積極的更新和活躍的用户羣體,我的主頁主題 hexo-theme-tranquility 便使用了該庫進行字體壓縮。但需要注意,這些庫目前都不支持可變字體的提取,所以當你進行字體提取時仍然可能需要加載多字重子字體文件。
參考資料
[1] PostScript[EB/OL]//Wikipedia. (2023-02-06)[2023-03-08]. https://en.wikipedia.org/w/index.php?title=PostScript&oldid=1...
[2] TrueType[EB/OL]//Wikipedia. (2023-02-14)[2023-03-08]. https://en.wikipedia.org/w/index.php?title=TrueType&oldid=113...
[3] OpenType[EB/OL]//Wikipedia. (2023-02-12)[2023-03-08]. https://en.wikipedia.org/w/index.php?title=OpenType&oldid=113...
[4] PETERCON. Recommendations for OpenType Fonts (OpenType 1.9) - Typography[EB/OL]. (2021-12-09)[2023-03-08]. https://learn.microsoft.com/en-us/typography/opentype/spec/re...
[5] 可變字體[EB/OL]//維基百科,自由的百科全書. (2021-08-19)[2023-03-08]. https://zh.wikipedia.org/w/index.php?title=%E5%8F%AF%E5%8F%98...
等