網頁字型與 SEO:中文字型的體積、FOIT 與 FOUT
字型是中文網站最容易被忽略的效能問題。一個英文網站載入三種字重可能只多花 100KB,同樣的事在中文網站上是 好幾 MB。
更麻煩的是,字型同時影響兩個 核心指標:文字晚顯示會拖累 LCP ,換字時的重新排版會計入 CLS 。
中文字型為什麼這麼大
差別在字數。
| 字形數量 | 單一字重壓縮後 | |
|---|---|---|
| 拉丁字母字型 | 約 200 以內 | 20-40KB |
| 繁體中文常用字 | 約 13,000 | 1-3MB |
| 中日韓統一表意文字 | 20,000 以上 | 4MB 以上 |
每一個字都是獨立的向量輪廓,字數多寡直接決定檔案大小。所以中文字型不是「壓縮一下就好」,而是必須 只載入真的會用到的字。
FOIT 與 FOUT
字型還沒載入完的那段時間,瀏覽器要決定文字怎麼顯示,兩種選擇各有名字。
| 現象 | 全名 | 行為 | 後果 |
|---|---|---|---|
| FOIT | Flash of Invisible Text | 字型載入完成前 不顯示文字 | 一段空白,使用者讀不到任何東西 |
| FOUT | Flash of Unstyled Text | 先用備援字型顯示,載入完再換 | 換字時閃一下、可能位移 |
中文網站應該選 FOUT
FOIT 在英文網站上可能只是 100 毫秒的空白,感覺不出來。但中文字型要載入數 MB,那段空白可能長達數秒,使用者面對的是一片空白的頁面,而 LCP 也會一併被算進去。
先用系統字型把內容顯示出來,至少讀得到。
控制這件事的是 font-display 屬性,各個值的行為差異見 字型顯示 font-display 。
三種對策
| 對策 | 解決什麼 | 難度 |
|---|---|---|
| 子集化 | 檔案太大 | 中 |
font-display | 空白與閃爍 | 低 |
| 預載 | 字型太晚開始下載 | 低 |
三者不是替代關係,而是要 一起用:子集化把檔案變小、font-display 決定載入期間怎麼顯示、預載讓它早點開始下載。
子集化
把字型切成多個分片,瀏覽器只下載頁面實際用到的那幾片:
/* 每一片宣告自己負責的字碼範圍 */
@font-face {
font-family: "MyFont";
src: url("/fonts/myfont-1.woff2") format("woff2");
unicode-range: U+4E00-4FFF;
font-display: swap;
}
@font-face {
font-family: "MyFont";
src: url("/fonts/myfont-2.woff2") format("woff2");
unicode-range: U+5000-5FFF;
font-display: swap;
}也可以走另一條路:掃過網站所有文字,只產生 實際出現過的字。靜態網站特別適合這招,常能把數 MB 壓到 100KB 以內。做法見 中文字型子集化 。
font-display
@font-face {
font-family: "MyFont";
src: url("/fonts/myfont.woff2") format("woff2");
font-display: swap; /* 立刻用備援字型,載完再換 */
}預載
字型的下載通常晚一步,瀏覽器要先解析 CSS、算出哪些元素用到這個字型,才會開始下載。用 preload 可以讓它提早開始:
<link
rel="preload"
href="/fonts/myfont.woff2"
as="font"
type="font/woff2"
crossorigin
>減少換字時的位移
備援字型與目標字型的字寬、行高不同時,換字的瞬間文字會重新排列,把下方內容往下推,這會計入 CLS 。
/* 調整備援字型的度量,讓它接近目標字型 */
@font-face {
font-family: "FallbackAdjusted";
src: local("Microsoft JhengHei");
size-adjust: 97%;
ascent-override: 88%;
descent-override: 12%;
}
body {
font-family: "MyFont", "FallbackAdjusted", sans-serif;
}還有一個選項:不用網頁字型
系統字型堆疊是完全合理的選擇
沒有額外請求、沒有閃爍、沒有位移、沒有第三方依賴。如果品牌沒有強制指定字型,這是最省事的做法。
body {
font-family:
system-ui, -apple-system, "Segoe UI", "Noto Sans TC",
"PingFang TC", "Microsoft JhengHei", sans-serif;
}省下的時間可以拿去優化 圖片 ,那邊的回報通常更大。
這一組還有這些主題
| 主題 | 說明 |
|---|---|
| 字型顯示 font-display | swap、optional、fallback 的行為差異與預載時機 |
| 中文字型子集化 | unicode-range 分片、依實際用字產生子集、woff2 壓縮 |
| 阻塞渲染的 CSS 與 JavaScript | 關鍵樣式內嵌、defer 與 async 的選擇 |
常見問題
中文字型為什麼這麼大?
字數差距造成的。英文字型只需要幾十個字母加標點,總共不到兩百個字形;中文光是常用字就上萬個,涵蓋整個中日韓統一表意文字區更超過兩萬。每個字都是獨立的向量輪廓,所以單一字重壓縮後仍常在數 MB 以上。
FOIT 和 FOUT 哪一個比較好?
多數情況選 FOUT。它先用系統字型把文字顯示出來,字型載入完再換掉,使用者至少讀得到內容;FOIT 則是在字型載入完成前完全不顯示文字,中文字型動輒數秒,那段空白對體驗與 載入速度指標 都不利。
不用網頁字型是不是最快?
就效能而言確實是。改用系統字型堆疊沒有任何額外請求,不會有閃爍也不會有版面位移。如果品牌沒有強制指定字型,這是最省事的選擇,可以把力氣放在別的優化上。
字型會影響版面穩定度嗎?
會。備援字型與目標字型的字寬、行高不同時,換字的瞬間文字會重新排列,把下方內容推移,計入 累積版位偏移 。可以用 size-adjust 這類調整備援字型度量的屬性讓兩者對齊,減少換字時的跳動。
Google Fonts 和自架哪個好?
各有取捨。Google Fonts 省事且已做好分片,但多一次跨網域連線;自架能完全掌控子集內容與快取策略,也少一個第三方依賴,但要自己處理分片與更新。以中文字型來說,自架加上自訂子集通常能壓到更小,比較見 中文字型子集化 。