先曬一下結果的畫面,也可以用 Chrome 或 Safari ,打開這裡看 demo(目前 Firefox 不支援):
以上全都是用 CSS 做出來的,不是一個一個反白再選字體(要是這樣我也不用寫一篇了)。
要做到這一點,必須使用 CSS3 @font-face
提供的 unicode-range
descriptor 。這招也不是沒有人玩過,在 2011 年底,就有人拿來設定西文裡面 "&" (ampersand) 的字體了,而在中文圈裡,@ethantw 在 2011 年中期開始製作漢字標準格式・標點樣式,來修正不同漢字地區的標點符號,當前的版本也應用了 unicode-range
。
以下就來解釋如何完成的。
CSS3 @font-face 的 unicode-range
根據 W3C 的 spec ,unicode-range
是這樣用的:
@font-face {
font-family: MyCustomFont;
unicode-range: U+00-7F; /* ASCII */
src: local(Helvetica), local(Arial); /* 先找 Helvetica ,沒有的話用 Arial */
}
這樣子的話,在 CSS 裡面就可以使用 font-family: MyCustomFont
,但是它只會套用在 U+00 到 U+7F 這些字元(Basic Latin,即 ASCII),即使 Helvetica 和 Arial 有提供其他字元,例如帶有重音符號的拉丁字母 é
(U+00E9,在 Latin-1 Supplement block),它還是不會套用這個字體。
unicode-range 的寫法
unicode-range
的 syntax 有以下 3 種(範例由 W3C spec 而來):
U+416
- 單一個 code pointU+400-4FF
- 某個 code point 區間(含頭尾)U+4??
- 尾碼任意的 code point,以這個例子來說,等義於U+400-4FF
。
如果要指定多個 ranges ,就是用逗號 ,
分開:
@font-face {
/* ... */
unicode-range: U+123, U+456-7FF, U+9??;
}
unicode-range
預設值是 U+0-10FFFF
,也就是涵蓋了所有 Unicode 的 code point space,白話的意思就是「不寫的話,這個 font face 要套用到所有字元」。
對同一個 font-family 的特定 unicode-range 設字體
這招在 W3C 的 spec 有教,以下的例子是「拉丁字、注音符號、日文假名用特別的字體,其他用預設的 Heiti TC(如果沒有 Heiti TC,就使用微軟正黑體)」。我們都知道,Heiti TC 的拉丁字、注音符號、日文假名都很醜,至於微軟正黑體是為了在 Windows 7 上面 Demo 用的:
@font-face {
font-family: MyCustomFont;
src: local(Heiti TC), local("微軟正黑體");
/* no unicode-range; default to all characters */
}
/* Latin characters 專用 */
@font-face {
font-family: MyCustomFont; /* 同樣的 font-family */
unicode-range: U+00-024F; /* Latin, Latin1 Sup., Ext-A, Ext-B */
src: local(Helvetica), /* OS X preferred */
local(Arial); /* Other OS */
}
/* 注音符號專用 */
@font-face {
font-family: MyCustomFont; /* 同樣的 font-family */
unicode-range: U+3100-312F; /* Bopomofo */
src: local(LiHei Pro), /* OS X */
local("微軟正黑體"); /* Windows Vista+ */
}
/* 日文假名專用 */
@font-face {
font-family: MyCustomFont; /* 同樣的 font-family */
unicode-range: U+3040-30FF; /* Hiragana, Katakana */
src: local(Hiragino Kaku Gothic Pro), /* OS X */
local(Meiryo); /* Windows Vista+ */
}
body {
font-family: MyCustomFont, sans-serif;
}
最後的結果,就是拉丁字、注音符號、日文假名用了另一種字體,而其他的文字則是用 Heiti TC;在 Windows 上面,則是使用微軟正黑體(假設使用者沒有自行安裝 Mac OS X 的字體)。
覆寫 Generic Family
Generic Family 就是 sans-serif 、 serif 這些基本的 style 。我在嘗試 @font-face
的時候,很好奇能不能把 font-family
指定成 Generic Family ,用來覆寫瀏覽器預設(或在偏好設定裡指定)的這些字體。實際試了一下,還真的可以,只要把上面的 CSS 裡面的 MyCustomFont
改成 sans-serif
,然後把 body
的 font-family
設成 sans-serif
,效果就跟之前一樣。
最終效果
文章一開頭的效果跟上面所示的例子其實不太一樣:
- 沒有預設字體,交給瀏覽器決定。
- 漢字用 Heiti TC
- 其他一樣
並且把 serif
也加進來。實際 demo 在此。
後記:Web Font
會做這個實驗,是前幾天看到 @ethantw 做的漢字標準格式・標點樣式,可以讓標點符號符合台、港式(置中)或中、日式(左下角)的標點。我很是好奇他怎麼能夠只針對標點符號去設定字體,於是打開了他的 CSS ,發現他在 @font-face
裡面使用了 unicode-range
。
我以前只知道 @font-face
拿來玩 Web Font,也就是說即使你的電腦裡沒有這個字體,也可以讓瀏覽器去下載並套用。現在才知道 @font-face
裡面可以寫 unicode-range
並且重覆寫 font-family: MyCustomFont
來製作出混合了數種字體的新字體。
事實上,上一次 Chrome 18 字體亂象發生時,我曾經嘗試在 User Agent Stylesheet (Custom.css
)裡面覆寫 sans-serif
的字體為 Helvetica
,想說這樣應該可以讓 Chrome 的字體 fallback 機制回到 OS X 處理。但那時候這樣做卻沒有成功,所以轉而去搞 Extension 。日前 Safari 6 也出現了同樣的功能,於是試了一下 custom stylesheet ,還真的可以 hack 掉 fallback 機制,那時候再回去 Chrome 試這招 override sans-serif
的 hack,竟然就可以了。
不過說到 Web Font 這技術,因為設計給漢字文化圈的字體都比較大(以 MB 為單位,因為字元多),所以這項技術只流行在歐美的網站(用拉丁字母,數十 KB 而已)。當然台灣也有救世字在嘗試提供中文 Web Font 服務,最近的 HITCON 2012 也展示了這項服務的潛力。