只是要求瀏覽器顯示思源黑體或 Noto Sans TC 這款常見的網頁中文字型,Google Fonts 就得幫瀏覽器切出 105 個各自獨立的字型檔案,全部下載完加起來要 2MB 以上。換成英文字型 Roboto,同樣要求一般字重,Google Fonts 的樣式表裡只有 9 個 @font-face,其中涵蓋全部拉丁字母、數字、標點的那一個檔案只要 21.4KB。
多數人量網站速度時,盯著的是圖片有沒有壓縮、JavaScript 有沒有精簡,卻沒想到網頁中文字型才是拖慢速度的關鍵因素。PageSpeed Insights 或 Lighthouse 掃過一輪繁體中文網站,「避免龐大的網路酬載」這類診斷十之八九指向字型檔案,而不是照片或程式碼。這是中文網站特有的處境,同樣的做法搬到英文網站,Google Fonts 幾乎感覺不到重量。
問題不在哪個字型設計得差,而是網頁中文字型要涵蓋的字符數量,跟英文完全不是同一個量級,這個先天差距逼著每個決定都變成取捨,要清晰好看的品牌字型,還是要下載得快;要跨系統顯示一致,還是要省流量。測速工具老是點名字型檔案,正是這個落差最先浮上檯面的地方。
測速報告一致指向同一個元凶,中文字型檔案
用 PageSpeed Insights、Lighthouse 或 WebPageTest 這類工具測一個掛了 Google Fonts 中文字型的網站,Network 面板攤開來看,佔比最大的資源常常不是照片,也不是 JavaScript,而是那幾個 WOFF2 字型檔案。Lighthouse 的「避免龐大的網路酬載」或「減少未使用的 CSS/字型」這兩項診斷,點名的對象十之八九也是字型。這個現象在中文網站特別明顯,換成英文網站幾乎不會被抓到。
這不是哪一款中文字型設計得不好,而是網頁中文字型天生就得扛住比英文重得多的字符量。CJK(中日韓)字型要涵蓋的字符種類,是拉丁字型的數十倍起跳(後面段落會列出 Google 官方文件給出的精確字形量級對照),繁體中文雖然常用字沒有日文那麼誇張,但同樣是表意文字系統,這個量級差距一樣存在。
以目前的 Noto Sans TC 版本(v39)實測,只要求 Google Fonts 提供一般字重(400),回傳的樣式表就切出 105 個各自帶 unicode-range 的 @font-face 宣告,代表這個字重被拆成 105 個獨立的 WOFF2 檔案;把這 105 個檔案的大小全部加起來,總共是 2,247,084 位元組,約 2.14MB。如果網站同時掛正常與粗體兩種字重,@font-face 宣告數量會直接變成 210 條,剛好是單一字重的兩倍,流量門檻也跟著加倍。這組數字,正是網頁中文字型拖慢網站的核心根源。
同一個網站,Windows 與 Mac 顯示成兩種字型
同一個網頁,在 Windows 電腦打開是一種字距,換到 MacBook 打開卻明顯稀疏或緊湊,標題被截斷、按鈕裡的文字溢出邊框,這種狀況多半不是版面設計出了問題,而是字型在作怪。
根本原因在於兩家作業系統廠商各自內建的中文字型互不相容。Windows 內建微軟正黑體(Microsoft JhengHei),macOS 與 iOS 內建的是蘋方體(PingFang TC);Windows 沒有蘋方體、macOS 也沒有微軟正黑體。如果 CSS 的字型堆疊,也就是 font-family 裡列出的 fallback 順序沒有設好,兩套系統各自退回到不同的預設字型,字寬、字高跟著不一樣,版面自然跑掉。
這其實跟前面提到的「字型太重」是同一個難題的兩面。要嘛用網頁字型,讓所有裝置都下載同一套 Noto Sans TC 或思源黑體,換來跨平台一致的畫面,但要付出前面那組動輒 2MB 起跳的下載代價;要嘛乾脆放棄網頁字型,改用各系統內建的中文字型組成堆疊,完全不用下載,但得接受 Windows 與 Mac 使用者看到的畫面終究有些微差異。速度與跨系統一致性沒辦法同時要,關鍵仍然回到那組讓字型檔案重到需要切成上百塊的字符數量。
中文字元數量比英文多出兩個量級
往回追一層:為什麼網頁中文字型的檔案會重到需要切成上百塊?答案在字符數量的量級差距。英文只靠 26 個大小寫字母加上標點符號,就能排列組合出所有單字,一套字型只要畫好這幾百個字形就夠用。中文是表意文字,每個字都是獨立的圖形,沒有把幾個筆畫拼裝出新字這回事,字型檔案得把每一個常用字都真的畫出來、內建進去,字數一多,檔案自然跟著變大。
Google 官方文件對這個量級差距有直接的說法,拉丁字型通常每種字型只需要 100 到 1,000 個字形,CJK 字型收錄的字符數量可能超過 10,000 個。這不是哪一款中文字型設計得沒效率,而是與生俱來的結構性差距,英文字母有限、可以排列組合,中文沒有這條捷徑。
CJK 統一表意文字收錄超過兩萬字
這個萬位數字形量級不是含糊的形容詞,Unicode Consortium 官方碼表把它標得很精確,CJK 統一表意文字(CJK Unified Ideographs)主要區塊,碼位範圍從 U+4E00 到 U+9FFF,總共 20,992 個碼位全部已經指配給字符。這還只是「基本區」,不含後續陸續加入的擴充區。
當然,繁體中文網站不會用到全部兩萬多字。教育部訂出的標準常用字約有 4,808 字,加上一般人名、地名會用到的異體字與罕用字,實務上一套要撐起完整閱讀體驗的中文字型,動輒仍要收錄幾千字起跳,比英文字母表 26 個字母的規模,還是差了兩個數量級。

每個字重都要重新收錄全部字符
字符數量還只是靜態的量級差距,網頁中文字型還有一個容易被忽略的乘數效應,也就是字重。英文網站要用粗體,瀏覽器多半可以靠演算法模擬(font-synthesis),不用額外下載字型檔案;中文字型沒有這條捷徑,每一個字重都是設計師或字型生成流程重新畫過的完整字集,網頁上多掛一個字重,幾乎等於把前面那份龐大的字集重新下載一次。
前面提到的 105 個檔案、2.14MB,是 Noto Sans TC 單一字重(400)的量。實測同時向 Google Fonts 要求正常與粗體兩個字重(wght@400;700),回傳的 @font-face 宣告數量直接變成 210 條,正好是單一字重的兩倍。這證實 Google Fonts 對中文字型是每個字重各自完整切分,掛越多字重,流量門檻幾乎等比例往上加,不像拉丁字型有時能靠 font-synthesis 省下一份下載。
Google Fonts 中文字型的實際下載成本
字符數量差距講完,最實際的問題是,如果網站掛 Noto Sans TC 這款網頁中文字型,讀者的瀏覽器實際要下載多少。答案分兩層看,一層是「涵蓋這個字重全部字符」的理論上限,另一層是更貼近真實情境的「單篇文章實際用到的字」子集。兩層數字對照起來,才看得出 Google Fonts 的自動切分(unicode-range)省了多少,也才看得出即使省到極限,中文字型依然比英文字型的全部家當還重。
Google 官方文件說明,透過 CSS API 搭配 unicode-range,可以把檔案傳輸量減少約 90%,瀏覽器只需要下載頁面實際用到的那幾個字符區段,不必整包 2MB 以上的字型一次吞下去。這套機制確實聰明,但中文字符量級太大,省了九成之後剩下的量,往往還是壓不到英文字型的水準。
完整涵蓋所有字元,需要上百個字型檔案
為了不讓使用者一次背走整包字型,Google Fonts 把 Noto Sans TC 拆成上百個各自帶 unicode-range 的小檔案,瀏覽器解析網頁內容後,只挑其中涵蓋到的字符區段下載,不會把 105 個檔案全部抓完。這個切法本身是合理的優化,只是中文字集太大,切完之後區段數量本身就上看百位數,這是英文字型完全不會遇到的規模。
實測同樣以 400 字重為例,Noto Sans TC 被切成 105 個 unicode-range 分塊,全部下載完(等於內容涵蓋到這個字重全部繁體字符的極限情況)總計要 2,247,084 位元組,約 2.14MB。這個上限數字比較適合拿來提醒經營內容型網站的人:網站經營越久、文章數量越多、用到的生僻字越廣,瀏覽器累積下載到的字型分塊也會越接近這個上限,不是只有第一次造訪才會遇到這筆成本。
只挑文章用字的子集,仍比整組英文字型重
真實情境不會一次用到 105 個分塊,多數網頁也不需要涵蓋全部字符。用本篇文章開頭三段、約 560 字、192 個不重複繁體字的實際段落,透過 Google Fonts 的 text= 參數發出請求,Google 會用 HarfBuzz 引擎即時動態子集化,只回傳一個 @font-face,這個 WOFF2 檔案實測下載確認為 33,160 位元組,約 32.4KB。跟前面的 2.14MB 相比,這個數字看起來已經壓縮到很小。
問題是,這個經過極限子集化的 32.4KB,仍然比 Roboto 涵蓋全部拉丁字母、數字、標點的完整檔案(21,884 位元組,約 21.4KB)還重。換算下來,同樣是「一個字型檔案打包某種語言全部常用字符」,網頁中文字型的子集版本還是比英文字型的完整版本重了約五成(相當於 1.5 倍)。這個對照才是這篇實測最反直覺的一點:不是沒做優化,而是就算做到 Google 官方建議的極限子集化,一段中文短文用到的字型資料量,依然超過英文字型完全不做任何子集化的全部家當。

系統字型堆疊完全省下下載成本
第一種取捨最直接,乾脆不用網頁字型,改在 CSS 的 font-family 裡依序列出各作業系統內建的中文字型,完全不透過網路下載任何字型檔案。這個做法把速度優勢發揮到極限,也順便解決前面提到的跨系統顯示落差,因為不再有「等字型下載完成才顯示文字」的換裝期,也就沒有版面位移的風險。
Google 官方文件把這類內建字型稱為系統字型,說明系統字型是使用者裝置介面本身在用的預設字型,「由於字型已安裝,因此不需要下載」,並建議用 system-ui 作為字型系列,直接取用當前系統的預設字型;也可以自己列出明確的堆疊順序,業界通行的寫法是 -apple-system, "PingFang TC", "Microsoft JhengHei", "Noto Sans CJK TC", sans-serif,讓 Mac 優先用蘋方體、Windows 優先用微軟正黑體,兩邊都沒有的裝置最後退回內建的中文黑體或系統預設無襯線字。
代價當然存在,前面提到的問題不會憑空消失:Windows 與 Mac 顯示出來的字距、筆畫粗細多少還是有落差,只是不至於跑版到無法閱讀。這條路線比較適合追求速度優先、對品牌字型辨識度要求不高的內容型網站,例如以文字為主的部落格或新聞頁面,讀者在乎的是內容能不能快點看到,而不是標題字體是不是那一款獨特的品牌字。
字型子集化,只留文章真正用到的字
如果放不下有品牌識別度的網頁字型,不想只靠系統字型撐場面,字型子集化(font subsetting)是折衷路線,只把網站實際會用到的字符打包進字型檔,其餘沒用到的字形直接砍掉,不再整套塞給使用者。前面「實際下載成本」那節的兩組數字,105 個分塊對上一個 32.4KB 的子集檔案,講的就是子集化能把下載量壓到多低。
Google Fonts 本身就內建這種動態子集能力,透過 text= 查詢字串參數,指定網頁只需要顯示哪些文字,就能換回對應的極限子集,前面的實測就是用這個參數完成的。如果選擇自行代管字型,官方建議改用 glyphhanger 或 subfont 這類工具自己產生子集檔案,原理相同,只是把產生子集的工作從 Google 的伺服器搬到自己的建置流程裡。
子集化不是做一次就一勞永逸。網站內容一旦用到子集清單裡沒收錄的生僻字,那個字在畫面上就會顯示不出來,或者跳成備用字型,跟其他字混在一起很突兀,所以子集清單要隨著內容更新重新產生,不能一次做完就當作永久解法。另外要提醒一件容易被忽略的事,Google 官方文件特別提醒「務必檢查字型授權,確認是否允許子集化和自行代管」,不是所有商用中文字型都開放這樣處理。像 Noto 系列字型由 Google 與 Adobe 共同開發,採用開放字型授權,可以自由子集化與自行代管,選字型時不妨把授權條款是否開放當成優先條件之一。
font-display 決定字型未到位前的顯示方式
不管前面選哪一條路,系統字型、子集化、還是乾脆用完整的網頁字型,都可以再疊加一層調整,也就是 CSS 的 font-display 屬性,決定「字型檔案還沒下載完成之前」瀏覽器要怎麼顯示文字。這是成本最低的一種取捨,不用換字型檔案,只改一行 CSS 就能生效,適合當作前面幾種做法的補強。
MDN 官方文件與 W3C 的規格把 font-display 定義成五個值,各自對應不同的封鎖期與換裝期:auto 由瀏覽器自行決定;block 給一段極短的封鎖期,期間畫面留白等字型,加上沒有時間限制的換裝期;swap 幾乎不封鎖,先用備用字型顯示,字型一到就立刻換上;fallback 封鎖期極短,換裝期也壓縮到很短;optional 封鎖期同樣極短,而且完全不給換裝期,字型沒在時限內到位,這次瀏覽就固定用備用字型,不再換回。
Google 官方文件補上具體的毫秒數字:block 的封鎖期落在 2 到 3 秒;swap 封鎖期是 0 毫秒;fallback 封鎖期 100 毫秒、換裝期約 3 秒;optional 封鎖期同樣 100 毫秒、沒有換裝期。官方給的建議也很明確:「對大多數網站而言……效能:使用 font-display: optional,這是效能最佳的做法……內文使用的字型請使用 font-display: optional」,只有品牌宣傳或視覺獨特的元素,才建議用 swap 換取最終一定顯示品牌字型,代價是換字瞬間可能造成看得到的跳動。

這個選擇對網頁中文字型來說,比英文網站更需要謹慎。中文字型檔案體積遠大於英文,前面幾節的實測數字已經說明這一點,字型延遲下載完成的機率自然更高;一旦選 swap,換字瞬間造成的版面位移也會比英文網站明顯,因為中西文字的寬度、行高差異通常比不同英文字型之間的差異更大。這是為什麼內文文字特別建議用 optional,盡量避免因為字型延遲載入而造成畫面跳動,保留 swap 給願意承受這個代價、也確實需要品牌字型出現的標題或視覺元素。
自行代管字型,換取控制權也換來維護責任
第四種取捨方向是自行代管,不管是完整字型還是子集化後的版本,把字型檔案放在自己的主機或 CDN 上,不再透過 Google Fonts 這層第三方連線。好處很直接,瀏覽器原本要先連一次 fonts.googleapis.com 拿樣式表,再連 fonts.gstatic.com 拿實際字型檔案,這兩趟跨網域的往返時間可以省下來;自己掌控檔案,也能完全決定要收錄哪些字符、搭配什麼樣的快取策略,不受 Google 那套自動化規則限制。
不過 Google 官方文件對這個「理論上更快」的說法反而潑了盆冷水:「紙面上,使用自行代管字型應該有更好的效能,因為省掉了第三方連線的建立;但實務上,這兩種做法的效能差異沒有那麼清楚」,並直接引用網路年鑑(Web Almanac)的調查結果,使用第三方字型的網站,算繪速度反而比使用第一方(自行代管)字型的網站更快。官方文件同時附上但書:如果要考慮自行代管,得先確認網站有用內容傳遞網路(CDN)並支援 HTTP/2,「沒有用到這些技術,自行代管字型帶來效能提升的機率就低很多」。換句話說,自行代管不是把字型檔案上傳到主機就結束,而是要自己重做一次 Google Fonts 原本內建的那些優化:子集化、WOFF2 壓縮、依瀏覽器提供合適格式,這些工作全部要自己扛下來,沒做好反而比繼續用 Google Fonts 更重。
這段官方說法直接破解「自己架字型一定比較快」這個常見的直覺誤解——連 Google 自己的文件都承認,跨來源下載不必然比較慢。要判斷值不值得自行代管,得先誠實盤點自己的網站有沒有 CDN、有沒有能力維持 HTTP/2 連線,而不是無條件推薦這條路。
值得特別點名的是,Google 官方文件也提到,自行代管字型建議額外套用字型子集化和 WOFF2 壓縮這類第三方字型供應商通常自動提供的最佳化設定,並且特別寫明「為中日韓語言最佳化字型可能特別困難」。這句話直接點出網頁中文字型自行代管的工作量,比英文字型大上不少,前面提到的子集化維護成本,會因為自行代管而全部落在自己身上。
WordPress 網站掛載自架字型的位置
決定要自行代管之後,下一個問題是實際該去哪裡動手。使用傳統 PHP 佈景主題的 WordPress 網站,通常在 functions.php 裡用 wp_enqueue_style() 載入一份自訂的樣式表,樣式表裡再用 @font-face 宣告子集化後的字型檔案路徑;也可以直接把 @font-face 規則寫進主題既有的 CSS 檔案。
如果網站用的是區塊主題(FSE,全站編輯),設定的位置不一樣,字型家族與對應的字型檔案網址是定義在 theme.json 的 settings.typography.fontFamilies 裡,編輯器與前台都會讀取這份設定檔來套用字型。兩種做法路徑不同,重點相同:前面幾節講的子集化、WOFF2 壓縮、快取標頭這些功課要先做完,再把處理好的檔案路徑接進主題設定,而不是直接把原始、未經處理的完整字型檔案上傳了事。

三個步驟,動手驗證自己網站的字型成本
前面談的每一種取捨,最後都得回到自己的網站實際測一次,才知道有沒有效果,不是看理論數字就夠。三個步驟都不需要額外的工具,打開瀏覽器就能動手。
第一步,打開瀏覽器的開發者工具,切到 Network 面板,把請求類型篩選成 Font,重新整理頁面,看看目前網站的字型檔案總共下載了幾個、加起來多少位元組。這個畫面就是本篇一路測到的那些數字的來源,自己網站的答案可能遠比想像中重。
第二步,跑一次 Lighthouse 或 PageSpeed Insights,看診斷報告裡跟字型有關的建議項目有沒有被點名,例如「避免龐大的網路酬載」或「確保文字在網頁字型載入期間保持可見」。Google 官方文件說明,Lighthouse 可以自動化這項檢查工作,確保網站遵循網頁字型最佳化的做法;如果不確定字型是不是及時被要求下載,也可以在開發者工具「網路」面板的時間軸分頁裡,查看字型請求實際發生的時間點。
第三步,挑本篇提到的其中一種取捨方案動手改,改用系統字型堆疊、把網頁字型換成子集化版本、調整 font-display 的值,或是把字型檔案搬到自己主機上,改完之後重新跑一次前面兩個步驟,拿改動前後的數字直接比較。真正確認下載量下降、診斷項目消失了,才算是這次調整真的有效果,而不是憑感覺覺得應該會比較快。
網頁中文字型會不會拖慢網站,答案從來不是單一個「用」或「不用」能回答,而是取決於要不要品牌字型的辨識度、能不能接受跨系統的顯示差異、有沒有餘力維護子集清單與快取設定。這幾個決定擺在一起看,其實就是拿速度、一致性、維護成本互相交換,沒有哪一種做法能同時把三樣都拿到手。
先照前面三個步驟,看清楚自己網站現在的字型重在哪一層,再回頭挑一個跟網站體質相配的做法動手調整,比繼續照抄別人的做法更有把握。這個取捨會隨著網站內容增加、字型技術演進持續變動,值得定期回頭測一次,而不是設定一次就當作永久解答。
