字體子集優化如何加快網頁載入速度?拆解技術原理與實作重點

Published on: | Last updated:

最近在看網站速度的東西... 唉,弄這個真的很煩,但又不能不做。🙄

剛好看到一個點,關於「字體」。嗯... 沒錯,就是那個我們每天在用的網頁字體。尤其是中文字體,一個檔案就好幾 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 值最高的選擇。雖然有點維護成本,但對效能的提升非常明顯。只要記得把它加到你的開發流程裡,其實也沒那麼可怕。

好了,今天就先聊到這... 感覺腦細胞死了一堆。希望對你有幫助。😴

對了,聊了這麼多,你自己的網站有被中文字體拖慢過嗎?或是你有用過什麼更酷的方法?留言分享一下吧 👇

Related to this topic:

Comments

  1. profile
    Guest 2025-05-15 Reply
    嗨!我對於網站字體載入速度的提升非常感興趣,想請教一下有關字體子集優化的資源或工具推薦!如果有任何經驗分享也很歡迎喔!謝謝!
  2. profile
    Guest 2025-04-25 Reply
    這篇文章真是太有幫助了!我想請教一下,除了字體子集優化之外,有沒有其他更有效的工具或方法可以進一步提升網站速度呢?期待你的分享!
  3. profile
    Guest 2025-04-01 Reply
    嘿各位站長!之前幫客戶做字體子集優化時也踩過坑,後來發現用Chrome的Lighthouse工具抓載入瓶頸超有用~大家有試過這招嗎?可以聊聊你們的實戰經驗啊!