最近在看網站速度的東西... 唉,弄這個真的很煩,但又不能不做。🙄
剛好看到一個點,關於「字體」。嗯... 沒錯,就是那個我們每天在用的網頁字體。尤其是中文字體,一個檔案就好幾 MB,真的是拖慢速度的元兇之一。所以今天想聊聊「字體子集化 (font subsetting)」這個東西,聽起來很技術,但其實概念... 意外地單純。
先說結論
簡單講,就是把你用不到的字,從字體檔裡全部刪掉。一個完整的字體檔可能包含上萬個字,但你的網頁可能只用了其中幾百個。那... 其他的字留著幹嘛?佔空間而已。把它們清掉,字體檔案變小,下載變快,網頁就跟著變快了。就是這麼回事。
所以,真的有差這麼多嗎?
差很多。真的。你可能沒什麼感覺,但訪客用的網路不一定跟你一樣快啊。
想像一下... 你的公司網站為了質感,買了一個超美的中文字體。結果那個字體檔 `beautiful-font.ttf` 壓成 woff2 之後,還是有 4MB。 對用光纖上網的人可能沒差,但如果是在外面用 4G 網路,甚至訊號不好... 光下載這個字體檔就要等好幾秒。體感上就是一片空白,或是文字突然「跳」一下,很煩。
但如果做了子集化,把網站上所有用到的 1500 個中文字、加上英文、數字符號... 全部打包成一個新的字體檔。檔案大小可能就從 4MB 變成... 250KB。這差別就大了,下載時間從幾秒鐘變成零點幾秒,幾乎無感。對使用者體驗和 Google 的一些評分(像 CLS)都有幫助。
好吧,那...要怎麼做?
嗯... 概念上,我們是透過 CSS 的一個屬性 `@font-face` 裡的 `unicode-range` 來達成的。
這東西就有點像是在跟瀏覽器說:「嘿,我現在給你這個 `font-small.woff2` 檔案,但它裡面只有 A 到 Z 的字母喔。所以只有在網頁上出現 A-Z 的時候,你才需要用它。」你可以準備好幾個子集檔案,一個管英文、一個管常用中文、一個管特殊符號等等。瀏覽器會自己判斷要下載哪個,滿聰明的。
當然,你不會想手動一個個字去切。這時候就需要工具了。如果你是工程師,可能會用到像 Python 的 `fonttools` 函式庫裡面的 `pyftsubset` 這個指令。 或是也有一些打包工具,像 `font-spider`,它會自動去爬你的 HTML 頁面,看你用了哪些字,然後幫你把字體檔切好。 過程大概就是跑個指令,然後等它產出檔案。
中英文網站,狀況不太一樣
說到這個,處理英文字體跟中文字體,那個複雜度... 真的是不同等級的。這也是我想特別拿出來講的點。
如果你的網站是純英文,那事情很單純。基本上就是 ASCII 字元範圍,從 `U+0020` 到 `U+007E`,包含了所有大小寫字母、數字、還有基礎標點符號。子集化非常簡單,檔案也可以壓到非常小。
但... 中文就麻煩了。常用字就有幾千個。 你要怎麼知道你的網站到底用了哪些字?
這裡就有兩種思路,也正好可以比較一下國外服務和我們自己土炮做法的差異:
- 國外服務的懶人包作法 (以 Google Fonts 為例): Google Fonts 其實有提供一個很方便的功能,你可以在載入字體時,加上一個 `&text=` 的參數,後面接上你想要的文字。例如,你只要一個標題「關於我們」需要特殊字體,你就可以這樣用。它會動態產生一個只包含這四個字的超小字體檔給你。超方便,但... 這只適合用在很少、而且固定的文字上。如果整個網站都要用,這方法就不行了。
- 在地的土炮精神 (自己動手): 對於一個完整的繁體中文網站,比較徹底的做法還是得靠自己。你需要先用爬蟲工具掃過整個網站,把所有出現過的不重複文字全部抓出來,存成一個清單。然後,拿這個清單去跑 `pyftsubset` 之類的工具,告訴它:「這是我要的字,幫我打包一個!」 這個方法最累,但效果也最好,可以做到最極致的優化。很多台灣的開發者或公司處理中文字體,基本上都是走這個路線。
所以你看,沒有最好的方法,只有最適合你現在情境的方法。
聽起來很棒,但...有什麼坑?
當然有。天下沒有白吃的午餐嘛。😅
最大的問題就是... 如果你少放了字怎麼辦?例如,你的網站有個留言區,你把所有「靜態頁面」的文字都做了子集。結果有個使用者留了一句言,裡面剛好有個字是你沒包進去的... 那個字在頁面上就會變成一個空心的方塊「□」,俗稱「豆腐塊 (tofu)」。超糗的。 這在有使用者生成內容 (UGC) 的地方特別容易發生。
另一個問題是維護。每次網站新增內容、改了文案,理論上... 你都要重新跑一次子集化的流程,產生新的字體檔。如果沒有自動化處理好,這件事會變成一個很煩人的人工步驟。忘記做,就是等著「開天窗」出現豆腐塊。
三種做法,挑一個適合你的
所以,綜合看下來,大概有幾種選擇。我整理了一下,你看哪種適合你。
| 做法 | 適合情境 | 效能影響 | 維護成本 |
|---|---|---|---|
| 直接用完整字體檔 | 嗯... 真的不在意速度、或是只有內部系統用的時候吧。 | 最差的。尤其在中文字體,隨便都好幾 MB,手機上載入很痛苦。🐢 | 幾乎沒有。上傳檔案,CSS 寫好路徑,收工。最無腦 👍 |
| 靜態子集化 (Static Subsetting) | 內容不太會變的網站。像是公司官網、活動頁、作品集。 | 非常好!可以把檔案壓到很小,載入速度超快。🚀 | 中等。每次更新網站文案,就要記得重新產生一次字體檔。需要建立流程,不然會忘。 |
| 動態子集化 (Dynamic Subsetting) | 內容一直變的網站,像新聞網站、論壇、電商。 | 也很棒。但通常是後端即時服務,第一次產生會慢一點,之後靠快取。 | 最高。通常要自己架設服務或是用 Adobe Fonts 這種付費服務,一般小專案不太會這樣搞。 |
我自己覺得啦... 對大部分中小型的專案來說,「靜態子集化」應該是 CP 值最高的選擇。雖然有點維護成本,但對效能的提升非常明顯。只要記得把它加到你的開發流程裡,其實也沒那麼可怕。
好了,今天就先聊到這... 感覺腦細胞死了一堆。希望對你有幫助。😴
對了,聊了這麼多,你自己的網站有被中文字體拖慢過嗎?或是你有用過什麼更酷的方法?留言分享一下吧 👇
