iT邦幫忙

2023 iThome 鐵人賽

DAY 2
0

在當今的網頁開發中,優化效能始終是一個追求的目標。我們都希望在短時間內,讓使用者得到最好的體驗。

於是,我們在開發過程中,努力地優化Lighthouse上的指標分數,其中透過code splitting以及lazy loading的方法,成功優化了網頁第一次渲染的速度,達到相當滿意的結果。然而,在遇到render-blocking,就是另外一個頭痛的問題。

當請求一個資源的時候,如果該資源存取完畢前無法觸發 window.onload 的事件,就稱作是 render-blocking。

透過深入分析,我們發現了一個不小的問題:載入Google Font字體。雖然這些精美的字體為我們的網頁增添了許多質感,但它在渲染過程中造成的堵塞卻是無法忽視的。畢竟,誰不想要一個既好看又快速的網站呢?

於是,我們開始著手解決這一問題。外部腳本的加載,我們都知道可以使用async或defer等方法優化,但Google Font的加載卻主要是透過<link>載入,這使得優化變得有些許的困難。但困難不代表不可能,下面我會一步步地為大家解釋。


首先,我們先了解一下通常的Google Font載入方法:

<link href="https://fonts.googleapis.com/css2?family=Lato:wght@300;400;700&
family=Noto+Sans+TC:wght@100;300;400;500;700&display=swap" rel="preload" as="style"/>

這樣的做法會導向一個CSS文件,該文件包含@font-face規則,而這些規則則由css下載字體檔,並套用。

hint:如果已經確定只需要某幾個字可以在網址後面輸入&text=xxx,google的cdn會自動只下載所需的字體檔。

@font-face {
  font-family: 'Lato';
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  src: url(https://fonts.gstatic.com/s/lato/v24/S6u9w4BMUTPHh7USSwiPGQ3q5d0.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
...

現在,讓我們來看如何優化這個過程。

以下是優化後的代碼:

<html lang="zh-Hant-TW">
... 
<link rel="preconnect" href="https://fonts.googleapis.com" crossOrigin="anonymous" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="anonymous" />
<link href="https://fonts.googleapis.com/css2?family=Lato:wght@300;400;700&
family=Noto+Sans+TC:wght@100;300;400;500;700&display=swap" rel="preload" as="style"/>
<link rel="stylesheet"
	href="https://fonts.googleapis.com/css2?family=Lato:wght@300;400;700&family=Noto+Sans+TC:wght@100;300;400;500;700&display=swap"
	media="print"
	onload="this.media='all';"
/>
...
</html>
  • 首先,我們可以使用preconnect來提前建立與字體伺服器的連接,減少等待時間。

  • 接著,使用rel="preload"加速字體的載入,並使用media="print"和onload事件確保非同步載入,避免阻塞。

在這邊想補充:不同<link rel=xxx />的意義:

rel:

  • preconnect : 瀏覽器可以透過搶先發起到該來源的連線來改善使用者體驗,先執行TCP/IP解析域名的部分。
  • preload: 跟瀏覽器聲明取得的這個頁面很快需要的資源,您希望在頁面生命週期的早期、瀏覽器的主要渲染機制啟動之前開始載入這些資源。雖然安排以更高的優先權下載和快取腳本,但也不會載入和執行腳本。

在還沒有下載完自定義字體前,display=swap使用預設字體直到自定義字型加載完成後切換,然後利用media="print"這個屬性,讓下載完的字體檔,以列印模式在為預設,不要直接渲染在不同頁面區塊造成帾塞。

最後在window.onload後再一次渲染上去。

hint:在這邊使用Next.js做專案,有遇到<link>這個Node不支援onload="this.media='all';"這個語法,所以我們利用了一點小技巧:直接套用html-string來繞過這個問題:

<style
    dangerouslySetInnerHTML={{
    __html: `</style><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Lato:wght@300;700&family=Noto+Sans+TC:wght@300;500;700&display=swap"
    media="print"
    onload="this.media='all';"
    />`,
    }}
/>

藉由這種方法,我們成功地減少了渲染堵塞,提供了更好的使用者體驗。希望這篇文章對你們有所幫助,一起為更快速的網路世界努力吧!


參考資料:
[web] 內容 Image 預先或延遲載入(preload, lazy load, prefetch)
MDN:外部加載資源連結元素


上一篇
從點擊到顯示:整個網頁運作的神秘之旅
下一篇
如何深度優化圖片:從next/image學到的事
系列文
從點擊到顯示:深度解析網頁運作的神秘之旅8
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言