Google webFont 直接引入使用所產生的問題
在外部資源來說,以網頁最需要取得相關的圖片與型字資源後,才能進行後續程式碼的規劃,圖片載入頁面又由其重要,除非頁面是給容器固定的高寬度值,不然也會對頁面上的佔位空間有所影響。
此外字體部份影響上比較沒像圖片會和版面呈現上較直接,可以先透過網頁安全字體進行渲染,直到 webFont 取得資源後在將畫面上的字體做一次更動。以上的部份多少會影響到使用者體驗,透過取得資源的順序方式改善。
快取與取用資源
preload、prefetch 於 HTTP Cache 與 Memory Cache 的快取方式
 preload 和 prefetch 取得的資源都會存在 HTTP Cache 中,再放到 Memory Cache,不能快取的話就只會在 memory cache。
 preload 和 prefetch 在取得資源前會先查詢快取,若快取沒過期就用快取的檔案不再重抓。
資源優先取用順序
1. Highest: HTML, CSS, Fonts
 2. High: script (預載影像之前), 在 viewport 內的影像
 3. Medium: script
 4. Low: script (async), image, media
 5. Lowest: mismatched CSS, prefetch resources
preload、prefetch、preconnect
preload、prefetch、preconnect 標籤的使用概念
以近代主流瀏覽器來說,大約於 2020 年的前後也都有大約有支援 HTML 標籤屬性 rel 的用法,查看到 2021 後的瀏覽器上也大都可使用。
 caniuse – Resource Hints: preload
 caniuse – Resource Hints: prefetch
 preload:此資源對目前的頁面是必要的,請用最快的速度下載此資源。
 preconnect:此網頁不久後將來下載某個 domain 的資源,先行建立連線。
 prefetch:此資源等等才會用到,有空在下載。
關鍵轉譯路徑最佳化 HTML、CSS、JS,影響使用者體驗
關鍵轉譯路徑用來改善網頁效能,優先顯示與使用者要在網頁上執行的主要操作有關的內容。
 收到 HTML、CSS 和 JavaScript 位元組,再對程式碼進行必需的處理,到最後轉變為顯示像素的過程中還有許多中間步驟。將效能最佳化其實就是瞭解這些步驟中所有的活動,這就是所謂的關鍵轉譯路徑。
Optimized (優化) 與 Unoptimized (未優化) 的畫面渲染處理方式。
 
preload:開啟頁面優先取連結資源
preload:此資源對目前的頁面是必要的,請用最快的速度下載此資源。
CSS 與 JS 的使用
rel="preload" 標籤,以 as 指定 script 或是 style 資源類型。
1 2  | <link rel="preload" as="script" href="xxx.js"> <link rel="preload" as="style" href="xxx.css">  | 
script 一般放在 html 的最後面,等到 parse 完整個 html 被執行。
 重要的資源以 preload 是比較好的優化方式。相較之下使用非同步下載資源 async script 較會會產生出 block onload event (阻止加載事件)。
Font 的使用
 rel="preload" 標籤,以 as 指定 font 資源類型。
 crossorigin="anonymous" (跨域屬性設定) 列為需要加的屬性,以 anonymous mode CORS 方式取得資源,否則字體會被重複下載兩次。
1  | <link rel="preload" as="font" crossorigin="anonymous" type="font/woff2" href="xxx.woff2">  | 
HTML5 部份元素有 CORS 的支援,可見 HTML5標簽的crossorigin屬性,提供元素CORS跨域設定 一文。
preconnect:將連結的 domain 資源先建立好連線
preconnect:此網頁不久後將來下載某個 domain 的資源,先行建立連線。
1  | <link rel="preconnect" href="https://xxx.com">  | 
提前建立連線,瀏覽器在實際傳輸資源前有幾個需要的步驟。
 1. 向 DNS 請求解析域名
 2. TCP Handshake (TCP 交握)
 3. SSL Negotiation (HTTPS 連線)
 4. 連線建立完成,等待拿到資料的第一個 byte
以 preconnect 的使用上,基本上可應用於 CDN 或是 Streaming (串流媒體) 上,在切換頁面前可以先進行取得資源進入到快取,當連結下一頁時結省下時間開啟頁面所建立連結的時間。
prefetch:等下用到的資源待必較資源取得後接續取
 prefetch:此資源等等才會用到,有空在下載。
 prefetch 主要是用在同頁資源時預先載入,資源等頁面完全下載完以後以 Lowest (最低) 優先度下載。
 在同頁用 JS 的 AJAX 行為抽換局部內容,若資源檔過大,排於 preload 優先必取資源先渲染主要頁面後,之後以 prefetch 接著於背後取得後續資源,在處理畫面抽換區塊內容,可達到較好的呈現 (例如:抽換高解析圖檔抽換區塊會漸漸呈現圖片)。
preload 實作 Google webFont
以下以 Noto Sans Traditional Chinese 使用 link 方式戴入字體資源。
1 2 3  | <link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link href="https://fonts.googleapis.com/css2?family=Noto+Serif+TC:wght@900&display=swap" rel="stylesheet">  | 
preconnect 於主要資源取得後,再取 Google webFont (官方預設產生連結方式)
直接以 Google webFont 官方引入方式,透過 <link rel="preconnect"> 方式引入。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26  | <!DOCTYPE html> <html lang="en">   <head>     <meta charset="UTF-8" />     <meta http-equiv="X-UA-Compatible" content="IE=edge" />     <meta name="viewport" content="width=device-width, initial-scale=1.0" />     <title>Document</title>     <link rel="preconnect" href="https://fonts.googleapis.com" />     <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />     <style>       @import url('https://fonts.googleapis.com/css2?family=Noto+Serif+TC:wght@900&display=swap');       .font--NotoSerifTC {         font-family: 'Noto Serif TC', serif;       }       body {         font-size: 25px;       }     </style>   </head>   <body>     <p class="font--NotoSerifTC">       人皆生而自由;在尊嚴及權利上均各平等。人各賦有理性良知,誠應和睦相處,情同手足。       人皆生而自由;在尊嚴及權利上均各平等。     </p>   </body> </html>  | 
引入結果查看到開發者工具,會發現因為 <link rel="preconnect"> 取用字體資源,會於相關資源都引入後,在頁面結構產生時才進行取得字體,所以相關字體會是在後方。
 
小結:這樣引用字體資源的方式,有個好處是可配合上瀏覽器安全字體先處理畫面,待 webFont 資源取得後再進行重新更換顯示字體。
改用 preload 將字體於頁面優先取得
以思源繁中字體,引入的資源檔相當多,詳見 https://fonts.googleapis.com/css2?family=Noto+Serif+TC:wght@900&display=swap,每個 @font-face {} 中 src: url() 就是對應的字體資源。
針對 src: url() 相關的字體資源,直接置於 HTML head 結構中的 <link>,加入屬性 rel="preload" 與 as="font",並開啟頁面透過開發者工具查看。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87  | <!DOCTYPE html> <html lang="en">   <head>     <meta charset="UTF-8" />     <meta http-equiv="X-UA-Compatible" content="IE=edge" />     <meta name="viewport" content="width=device-width, initial-scale=1.0" />     <title>Document</title>     <link rel="preconnect" href="https://fonts.googleapis.com" />     <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />     <!-- 使用 css2 連結文件中的字型檔,以 preload 預先載入 -->     <link       rel="preload"       href="https://fonts.gstatic.com/s/notoseriftc/v17/XLY9IZb5bJNDGYxLBibeHZ0BvvMpbXxGSMoPW2CYaL4xcgZt2hLi5AU2hsKUwIdeS7qKC8bpy_5IYlDy.119.woff2"       as="font"       crossorigin     />     <link       rel="preload"       href="https://fonts.gstatic.com/s/notoseriftc/v17/XLY9IZb5bJNDGYxLBibeHZ0BvvMpbXxGSMoPW2CYaL4xcgZt2hLi5AU2hsKUwIdeS7qKC8bpy_5IYlDy.114.woff2"       as="font"       crossorigin     />     <link       rel="preload"       href="https://fonts.gstatic.com/s/notoseriftc/v17/XLY9IZb5bJNDGYxLBibeHZ0BvvMpbXxGSMoPW2CYaL4xcgZt2hLi5AU2hsKUwIdeS7qKC8bpy_5IYlDy.118.woff2"       as="font"       crossorigin     />     <link       rel="preload"       href="https://fonts.gstatic.com/s/notoseriftc/v17/XLY9IZb5bJNDGYxLBibeHZ0BvvMpbXxGSMoPW2CYaL4xcgZt2hLi5AU2hsKUwIdeS7qKC8bpy_5IYlDy.116.woff2"       as="font"       crossorigin     />     <link       rel="preload"       href="https://fonts.gstatic.com/s/notoseriftc/v17/XLY9IZb5bJNDGYxLBibeHZ0BvvMpbXxGSMoPW2CYaL4xcgZt2hLi5AU2hsKUwIdeS7qKC8bpy_5IYlDy.112.woff2"       as="font"       crossorigin     />     <link       rel="preload"       href="https://fonts.gstatic.com/s/notoseriftc/v17/XLY9IZb5bJNDGYxLBibeHZ0BvvMpbXxGSMoPW2CYaL4xcgZt2hLi5AU2hsKUwIdeS7qKC8bpy_5IYlDy.115.woff2"       as="font"       crossorigin     />     <link       rel="preload"       href="https://fonts.gstatic.com/s/notoseriftc/v17/XLY9IZb5bJNDGYxLBibeHZ0BvvMpbXxGSMoPW2CYaL4xcgZt2hLi5AU2hsKUwIdeS7qKC8bpy_5IYlDy.117.woff2"       as="font"       crossorigin     />     <link       rel="preload"       href="https://fonts.gstatic.com/s/notoseriftc/v17/XLY9IZb5bJNDGYxLBibeHZ0BvvMpbXxGSMoPW2CYaL4xcgZt2hLi5AU2hsKUwIdeS7qKC8bpy_5IYlDy.107.woff2"       as="font"       crossorigin     />     <link       rel="preload"       href="https://fonts.gstatic.com/s/notoseriftc/v17/XLY9IZb5bJNDGYxLBibeHZ0BvvMpbXxGSMoPW2CYaL4xcgZt2hLi5AU2hsKUwIdeS7qKC8bpy_5IYlDy.113.woff2"       as="font"       crossorigin     />     <link       rel="preload"       href="https://fonts.gstatic.com/s/notoseriftc/v17/XLY9IZb5bJNDGYxLBibeHZ0BvvMpbXxGSMoPW2CYaL4xcgZt2hLi5AU2hsKUwIdeS7qKC8bpy_5IYlDy.50.woff2"       as="font"       crossorigin     />     <style>       @import url('https://fonts.googleapis.com/css2?family=Noto+Serif+TC:wght@900&display=swap');       .font--NotoSerifTC {         font-family: 'Noto Serif TC', serif;       }       body {         font-size: 25px;       }     </style>   </head>   <body>     <p class="font--NotoSerifTC">       人皆生而自由;在尊嚴及權利上均各平等。人各賦有理性良知,誠應和睦相處,情同手足。       人皆生而自由;在尊嚴及權利上均各平等。     </p>   </body> </html>  | 
引入結果查看到開發者工具,會發現到相關的字體資源都提於前面,相關資源都完整取得後,才會透過渲染畫面。
 
小結:在取得資源時,因為是主要優先取得,如果裝置的網速不快,會產生過久的空白畫面。
JS 要規劃優先取得資源後才渲染畫面,另可使用 Web Font Loader (字體載入事件) 的 JS 插件,套件主要目的就是以 Javascript 的方式載入Web Font,並透過傳遞一些參數,來改變載入 Web Font 行為,待取得資源與字體載入完成後,才進行畫面渲染。
Web Font Loader 網頁字體裝載機 (繁中文件說明)
