改善 JavaScript 生態系統中的最大內容繪製。
在 Aurora 專案中,Google 一直與熱門的網頁架構合作,確保這些架構根據網站體驗核心指標打造良好效能。Angular 和 Next.js 已內嵌字型,詳情請參閱本文的第一部分。我們介紹的第二個最佳化是重要的 CSS 內嵌,現在在 Angular CLI 中預設為啟用,並在 Nuxt.js 中實作。
字型內嵌
在分析數百個應用程式後,Aurora 團隊發現開發人員經常會在 index.html
的 <head>
元素中參照字型,藉此在應用程式中加入字型。以下是加入質感設計圖示後的顯示效果範例:
<!doctype html>
<html lang="en">
<head>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
...
</html>
雖然這個模式完全有效且運作正常,但會封鎖應用程式的算繪作業,並引入額外要求。如要進一步瞭解具體情況,請參閱上述 HTML 所參照的樣式表原始碼:
/* fallback */
@font-face {
font-family: 'Material Icons';
font-style: normal;
font-weight: 400;
src: url(https://fonts.gstatic.com/font.woff2) format('woff2');
}
.material-icons {
/*...*/
}
請注意 font-face
定義如何參照 fonts.gstatic.com
上代管的外部檔案。載入應用程式時,瀏覽器必須先下載標題中參照的原始樣式表。
接著,瀏覽器會下載 woff2
檔案,最後再繼續轉譯應用程式。
有最佳化的機會,是在建構時下載初始樣式表,並將其內嵌在 index.html
中。這樣會在執行階段略過完整的 CDN 封包往返時間,縮短封鎖時間。
建構應用程式時,要求會傳送至 CDN,這會擷取樣式表並內嵌在 HTML 檔案中,將 <link rel=preconnect>
新增至網域。套用這個技巧後,得到以下結果:
<!doctype html>
<html lang="en">
<head>
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin >
<style type="text/css">
@font-face{font-family:'Material Icons';font-style:normal;font-weight:400;src:url(https://fonts.gstatic.com/font.woff2) format('woff2');}.material-icons{/*...*/}</style>
...
</html>
Next.js 和 Angular 支援字型內嵌功能
當架構開發人員在基礎工具中實作最佳化時,可讓現有和新應用程式更輕鬆地啟用最佳化功能,進而改善整個生態系統。
根據預設,Next.js v10.2 和 Angular v11 會啟用這項改善功能。兩者都支援內嵌 Google 和 Adobe 字型。Angular 預計會在 12.2 版中導入後者。
您可以在 GitHub 找到 Next.js 中的字型內嵌實作,並觀看這部說明 Angular 的最佳化說明影片。
內嵌重要的 CSS
此外,還包括內嵌重要的 CSS,藉此改善首次內容繪製 (FCP) 和最大內容繪製 (LCP) 指標。網頁上重要的 CSS 包含初始轉譯時使用的所有樣式。如要進一步瞭解該主題,請參閱延遲不重要的 CSS。
我們發現許多應用程式都是以同步方式載入樣式,導致應用程式無法顯示。快速解決問題的方法:以非同步方式載入樣式。不要使用 media="all"
載入指令碼,而是將 media
屬性的值設為 print
,並在載入完成後,將屬性值取代為 all
:
<link rel="stylesheet" href="..." media="print" onload="this.media='all'">
不過,這種做法可能會導致未設定樣式的內容閃爍。
上方影片顯示了以非同步方式載入網頁樣式的呈現方式。瀏覽器會先開始下載樣式,然後轉譯接著出現的 HTML,因此閃爍畫面會發生這種情況。瀏覽器下載樣式後,會觸發連結元素的 onload
事件、將 media
屬性更新為 all
,然後將樣式套用至 DOM。
從顯示 HTML 到套用樣式的期間,頁面的部分樣式不會改變。瀏覽器使用這些樣式時,我們會看到畫面閃爍,這會造成使用者體驗不佳,並會導致累計版面配置位移 (CLS) 出現迴歸情形。
「重要 CSS 內嵌」搭配非同步樣式載入,可以改善載入行為。條件工具可查看樣式表中的選取器並與 HTML 進行比對,藉此找出網頁中使用的樣式。找到相符項目時,Google 會將對應的樣式視為重要 CSS 的一部分,並內嵌於這些樣式。
以下面這段程式碼為例:
<head> <link rel="stylesheet" href="/styles.css" media="print" onload="this.media='all'"> </head> <body> <section> <button class="primary"></button> </section> </body>
/* styles.css */ section button.primary { /* ... */ } .list { /* ... */ }
在上述範例中,動物會讀取並剖析 styles.css
的內容,之後才將兩個選取器與 HTML 進行比對,並發現我們使用的是 section button.primary
。最後,條件會將對應的樣式內嵌到網頁的 <head>
中,進而產生以下成果:
<head> <link rel="stylesheet" href="/styles.css" media="print" onload="this.media='all'"> <style> section button.primary { /* ... */ } </style> </head> <body> <section> <button class="primary"></button> </section> </body>
將重要的 CSS 嵌入 HTML 後,您會發現網頁閃爍的情形如下:
重要 CSS 內嵌現已在 Angular 提供,且在 v12 中預設為啟用。如果您採用第 11 版,請在 angular.json
中將 inlineCritical
屬性設為 true
,即可開啟。如要在 Next.js 中啟用這項功能,請將 experimental: { optimizeCss: true }
新增至 next.config.js
。
結論
我們在這篇文章中探討了 Chrome 和網路架構之間的部分合作方式。如果您是架構作者,且瞭解我們在您的技術中遇到的一些問題,希望我們的發現可以啟發您採行類似的效能最佳化措施。
進一步瞭解改善項目。您可以參閱「Aurora 簡介」一文,瞭解我們對 Core Web Vitals 所做的任何最佳化工作。