網站載入很慢?中文字型很可能是元凶
約 8 分鐘
打開網站,版面空白三秒、五秒,文字才一次浮出來。這種狀況在中文網站出現的機率特別高,原因通常落在字型。一套中文字型的體積可能比網站其他所有資源加起來還大,而它偏偏又是會擋住文字顯示的資源,慢下來就直接反映在使用者盯著空白畫面的那幾秒。這篇說明怎麼判斷元凶是不是字型、該動哪幾個地方,以及每個做法的代價與長期維護成本。
1. 中文字型為什麼特別重
拉丁字型一個字重通常收 200 到 400 個字符,壓成 woff2 之後大約 20 到 40 KB。中文常用字就有五六千個,全字集收到兩萬以上,同樣壓縮完一個字重動輒 3 到 8 MB。差距是百倍起跳,不是多一點點。
體積還會再往上疊。可變字型把多個字重塞進同一個檔案,用起來方便,檔案也更大。中文網站又習慣「標題一套、內文一套」,等於同時載入兩份大檔。一個網站放兩套中文字型,光字型就可能超過站上其他所有資源的總和。
字型跟圖片還有一個關鍵差異:它會擋住文字繪製。圖片沒載完,旁邊的字照樣看得到。字型沒載完,那段文字就卡著不出現,或先用系統字型頂著再跳一次。使用者盯著空白畫面的那幾秒就是這樣來的,量測工具上會直接反映成 FCP 與 LCP 兩個數字難看。
從 Google 的字型服務載入中文時,它會把字型切成上百個小分片。看起來分散了,但頁面用到的字越散,實際下載的分片就越多,總量不會因此變小。受影響最深的是行動網路與較舊的手機,桌機接寬頻常常把問題整個藏起來,所以只測桌機的人會覺得沒事。
2. 怎麼確認慢的原因就是字型
最省事的方式是把網址丟進 Google 的 PageSpeed Insights,看它有沒有把字型列進「拖慢載入」的項目。想再確認一點,在瀏覽器按 F12 打開「網路」頁籤重新整理,看每個字型檔多大、下載花多久。
量的時候記下這四件事
- 改動前的分數與秒數。先用 PageSpeed Insights 記一次當基準,之後才有得比。
- 字型的總傳輸量與最慢的那一筆。網路頁籤停用快取後重新整理,篩選字型類型的檔案再看。
- 有沒有跑去外部服務拿字型。網址出現 fonts.googleapis.com 或 fonts.gstatic.com 就是。每多連一個外部網站,就多一段建立連線的等待。
- 行動裝置條件下的數字。把瀏覽器的網路節流與效能降速打開再測一次,數字才貼近真實使用者。
判斷的關鍵在時間點。如果畫面文字浮出來的時間,跟最後一個字型檔下載完成的時間貼在一起,元凶大致就確定了。再看一次頁面上最大的那個內容元素是誰,如果它是一段標題文字,字型的嫌疑就更高。
3. 四種解法,由易到難
這四步可以照順序做。前兩步當天就會有效果,後兩步需要一點工。四步全做完,一個原本載入多套中文字型的網站,把字型總量壓到 200 KB 以內是做得到的。
| 做法 | 省下什麼 | 代價 |
|---|---|---|
| 減少字型家族 | 每砍掉一套中文字型,就少一份幾 MB 的下載 | 設計上的變化少一點 |
| 內文改用系統字型 | 中文內文的下載量歸零,通常省下兩百多 KB 起跳 | 不同裝置看到的內文字體不完全一樣 |
| 把字型收回自己主機 | 省掉連往外部服務的等待,也能自己決定讓瀏覽器記住多久 | 要先確認授權允許自架 |
| 只保留用得到的字 | 一套只用在標題的中文襯線字型,處理完常見落在 100 KB 上下 | 要維持重新產生的流程,否則新文章會漏字 |
順序是有意義的。前兩步是砍掉不需要的東西,盤點站上實際用到幾套字,把只出現在一兩個區塊的裝飾性字型直接拿掉,做完通常就解掉大半問題。後兩步是把留下來的那套處理好,工比較多。每做完一步就重新量一次,才知道哪一步真的有效。
內文改用系統字型的意思是,直接指定讀者裝置上本來就有的中文字型,瀏覽器不必下載任何東西。常見的一組排法是 -apple-system、PingFang TC、Microsoft JhengHei、Noto Sans TC,最後接一個 sans-serif 當保底。
4. 只留用得到的字,代價在哪
工具面沒什麼玄機。有現成程式能掃出站上實際用到哪些字,產出精簡版字型檔並輸出成壓縮率較好的 woff2 格式,跑幾秒就結束。如果用的是可調粗細的字型,順便把粗細範圍限縮到實際會用到的區間,體積還能再降一截。
同一行文字裡混著子集字型與系統字型,讀起來會覺得哪裡怪,但又講不出是哪個字有問題。決定採用之前,要先確定自己有辦法維持重新產生的流程,否則過幾個月版面會慢慢花掉。
要控制這個風險,重點是讓重新產生變成自動的事。把產生子集接進建置流程或發文流程,新內容上線前自動跑一次,漏字就不會累積。字符來源建議直接從編譯後的頁面內容掃出來,比人工維護一份字表可靠得多。
沒辦法自動化的話,至少在標題字型的子集裡多收一份常用字表當緩衝,代價是檔案變大一些。另外把原始的完整字型檔與產生步驟留著,換人接手才重做得出來。上線前用實際文章內容目視檢查一遍標題與導覽列,漏字通常一眼就看得到。
5. 字還沒載完的那幾秒,畫面要顯示什麼
font-display 決定字型還沒下載完的期間,瀏覽器要怎麼處理那些文字。swap 會先用系統字型畫出來、字型到位再換掉,好處是文字不會消失,代價是換字瞬間的版面跳動。optional 讓瀏覽器在字型沒能即時到位時直接放棄這一次載入,版面最穩,代價是有些使用者第一次進站看到的是系統字型。
多數網站的內文用 swap 就好,至少不會整段空白。想完全消除版面跳動再考慮 optional,前提是接受部分使用者第一次看到的不是你選的字。真的很在意那一下位移的話,可以微調備用字型的度量(size-adjust、ascent-override 這兩個設定),讓它的字面寬度與行高接近正式字型,換字時的位移就會小到幾乎看不出來。
6. 自架字型順手解掉的幾件事
效能之外,把字型收回自己家還順手解掉兩件事。第一是安全設定變單純:網站可以規定只准跟哪些外部網站要東西,少兩個來源,這份名單就短一截,也比較好維護。第二是隱私:不必再向訪客揭露「你的連線資訊會被送到 Google 的字型服務」,德國那件 Google Fonts 判決之後,有歐盟訪客的網站對這點會比較在意。
自架之後有兩件事要順手設好。字型檔給長效快取,並讓檔名帶版本編號,改版時換檔名即可,回訪的人就不必重新下載。另外先確認授權:Noto 與思源系列採 SIL Open Font License,自架與子集化都在允許範圍內,商用字型則要逐一看合約怎麼寫。
7. 排除字型之後,還可能是什麼
字型處理完分數還是難看的話,接著看兩個地方。第一是圖片:沒壓縮的 JPEG、直接上傳的手機拍攝原圖,這些常常本身就是頁面上最大的那個元素。第二是網頁程式:程式一次做太多事的時候,畫面就算畫出來了也點不動,使用者會覺得卡。
字型之外的四個常見兇手
- 圖片沒有處理過。改用 WebP 或 AVIF,依版面實際尺寸輸出,並加上寬高避免載入時版面位移。
- 首屏那一張圖被延後載入。首屏以外的圖片延後載入是對的,首屏那張反而要拿掉延後,它通常就是決定畫面多久出現的元素。
- 一次載入太多程式。整包載入的套件、輪播與動畫函式庫,能拆的拆、能延後的延後。
- WordPress 的外掛與佈景主題。先看外掛數量與佈景自帶的資源,很多站光是停用兩三個用不到的外掛就有感。
這幾項查完通常就夠了。多數中文網站的載入問題停在字型與圖片這兩關,還沒輪到換主機那一步。
字型是少數改動範圍小、效果卻能直接反映在數字上的項目。一個原本從第三方載入多套中文字型的網站,把上面四步做完之後,畫面第一次出現文字的時間有機會從十幾秒降到兩秒以內,而且動到的只有字型載入方式,版面與內容都不必改。這些數字在不同測試環境會有落差,所以改動前後要用同一套條件對照,看趨勢比看單次分數可靠。
常見問題
- 網站用 Google Fonts 載入中文字型會不會拖慢速度?
- 會,而且中文網站的差距特別明顯。中文字型檔本身就大,再加上要多連兩個外部網站拿檔案,行動網路上尤其吃虧。載入多套中文字型的站,畫面第一次出現文字拖到十秒以上並不罕見。改成自己主機提供、只留用得到的字之後,通常能壓到兩秒附近。如果站上只用一套拉丁字型,影響就小很多,不必急著改。
- 中文字型子集化之後,新文章出現沒收錄的字會怎樣?
- 那一個字會退回系統字型顯示。單獨看不一定馬上發現,放在同一行標題裡就看得出粗細與筆畫風格對不上。解法是把重新產生子集接進發文或建置流程,或在子集裡多收一份常用字表當緩衝,代價是檔案變大。沒有維護流程的話,建議先做「減少家族」與「內文用系統字型」這兩步就好。
- 內文中文改用系統字型堆疊,各裝置看起來會差很多嗎?
- 會有差異。macOS 與 iOS 走蘋方、Windows 走微軟正黑或本機版 Noto Sans TC、Android 走思源黑體,字面寬度與行高不完全一致。內文尺寸下多數讀者不會特別注意,換來的是中文字型下載量歸零。若品牌對內文字型有嚴格要求,就得留著自架字型並接受它的體積。