使用 Angular Image 指令最佳化圖片

Kara Erickson
Kara Erickson
Leena Sohoni
Leena Sohoni

2022 年 5 月,Aurora 和 Angular 團隊宣布將合作為 Angular 開發圖片指令。這項指令最近已在 Angular 第 14.2 版中發布開發人員預覽版。本文將說明新的圖片指令 NgOptimizedImage 如何支援 Angular 中的圖片最佳化功能。

背景

圖片是網路使用者體驗中常見且重要的元素,99.9% 的網頁都會產生一或多個圖片的要求。圖片也是影響網頁重量的最大因素,每個網頁的平均大小為 982 千位元組

由於圖片的數量和大小不斷增加,可能會影響網頁效能,並影響網站體驗核心指標。在 2021 年,79.4% 的電腦版網頁的最大內容繪製 (LCP) 元素都是圖片。因此,我們許多人一直致力於追求最佳化圖片。

Aurora 團隊相信,只要善用架構的強大功能,就能為開發人員常見的挑戰提供內建解決方案。他們第一次涉足圖片最佳化領域,就是使用 Next.js 圖片元件。他們認為這個元件是測試場域,可用來測試改善圖片最佳化開發人員體驗 (DX) 是否能讓更多使用架構的應用程式獲得效能優勢。

Next.js 使用者 Leboncoin 提供的第一組結果令人振奮。Leboncoin 開始使用 next/image 後,LCP 大幅改善 (從 2.4 秒縮短至 1.7 秒)。之後,社群開始採用 next/image,導致符合 LCP 門檻的 Next.js 來源數量增加。不久之後,其他架構也要求類似功能,其中一個就是 Angular

因此,Aurora 諮詢了 Angular 和 Nuxt,為這些架構製作圖片元件的原型。Nuxt 圖片元件已於去年發布。我們已發布 Angular 圖片指令 (NgOptimizedImage),為 Angular 提供圖片最佳化預設值。

商機

Angular 是目前開發人員使用的領先 JavaScript 架構之一。HTTPArchive 在行動裝置上檢索的來源超過 5 萬個都使用了這個套件,且在 NPM 上每週下載次數達 近 300 萬次

過去一年 Angular 網站的 LCP。

從 Core Web Vitals 分數來看,符合「良好」LCP 門檻的 Angular 來源百分比仍有待改善。在 2022 年 6 月,只有 18.74% 的 Angular 網站在行動裝置上有良好的 LCP。在行動裝置和電腦上,超過 70% 的網頁都會使用圖片做為 LCP 元素,因此未經最佳化的 LCP 圖片,可能是 Angular 網站 LCP 較差的主要原因之一。

Angular 圖片指令旨在協助改善這些數字。

NgOptimizedImage 指令的 MVP

Angular 圖片指令的 MVP 是根據 Aurora 迄今建構的圖片元件所學到的經驗,並將設計調整為符合 Angular 的用戶端算繪體驗。許多標準圖片最佳化問題已透過以下方式解決:

  • 提供強大的預設值。
  • 擲回錯誤或警告,確保符合最佳做法。

設計重點如下:

  1. 智慧延遲載入

    使用者在網頁載入時看不到的圖片 (例如下捲圖片或隱藏的輪轉介面圖片),最好採用延遲載入。延後載入可釋出瀏覽器資源,以便載入其他重要文字、媒體或指令碼。大多數圖片都不是必要的,應採用延遲載入功能,但在 2021 年,只有 7.8% 的網頁使用原生延遲載入功能。

    Angular 圖片指令預設會延遲載入非重要圖片,並只會立即載入特別標示為 priority 的圖片。這麼做可確保大多數圖片都能以最佳方式載入。

  2. 優先處理重要圖片

    新增資源提示 (例如preloadpreconnect) 來優先載入重要圖片,這是建議的最佳做法。不過,大多數應用程式並未使用這些功能。根據 2021 年網路年鑑,只有 12.7% 的行動網頁使用預先連線提示,且只有 22.1% 的行動網頁使用預先載入提示。

    當圖片標示為優先時,圖片指令會在兩個方面發揮作用。

    • 它會將圖片的 fetchpriority 設為 "high",讓瀏覽器知道應以高優先順序下載圖片。
    • 在開發模式中,執行階段檢查會確認已納入與圖片來源相對應的 preconnect 資源提示。

    在開發模式中,指令也會使用 PerformanceObserver API 驗證 LCP 圖片是否已如預期標示為 priority。如果未標示為 priority,系統會擲回錯誤,指示開發人員將 priority 屬性新增至 LCP 圖片。

    最終,這種自動化和符合性組合可確保 LCP 圖片具有 preconnect 提示、fetchpriority 屬性值為 high,且不會延遲載入。

  3. 針對熱門圖片工具進行最佳化設定

    建議 Angular 應用程式使用圖片 CDN,因為這些服務通常會預設提供最佳化服務。

    此指令可提供特別吸引人的開發人員體驗 (DX),讓您在應用程式中設定圖片 CDN,鼓勵使用圖片 CDN。此指令支援載入器 API,可讓您在設定中定義 CDN 供應器和基本網址。設定完成後,您只需在標記中定義素材資源名稱即可。例如:

    // in module providers:
    provideImgixLoader('https://mysite.net/assets/')
    
    // in markup
    <img ngSrc="image.png" >
    <img ngSrc="image2.png" >
    

    這等同於加入下列圖片標記,並減少開發人員必須為每張圖片加入的標記。

    <img src="https://mysite.net/assets/image.png">
    <img src="https://mysite.net/assets/image2.png">
    

    圖片指令會提供內建的載入器,並為最熱門的圖片 CDN 提供最佳設定。這些載入器會自動格式化圖片網址,確保每個 CDN 都使用建議的圖片格式和壓縮設定。

  4. 內建錯誤和警告

    除了上述內建最佳化功能外,指令也提供內建檢查功能,確保開發人員在圖片標記中遵循建議的最佳做法。圖片指令會執行下列檢查。

    1. 未指定大小的圖片:如果圖片標記未明確定義寬度和高度,圖片指令會擲回錯誤。未指定大小的圖片可能會導致版面配置位移,進而影響網頁的累計版面配置位移 (CLS) 指標。為避免這種情況,建議您在圖片中指定 widthheight 屬性。

    2. 顯示比例:圖片指令會擲回錯誤,讓開發人員知道 HTML 中定義的 width:height 顯示比例與轉譯後圖片的實際顯示比例是否相近。這可能會導致圖片在螢幕上顯示不正確。發生這種情況的原因如下:

      1. 您誤將錯誤的尺寸 (寬度或高度) 定義為
      2. 如果您在 CSS 中以百分比定義一個維度,但未定義另一個維度 (例如,width: 100% 需要 height: auto,才能確保圖片在兩個維度中均能放大)。
    3. 超大圖片:如果圖片未定義 srcset,且內在圖片明顯大於算繪圖片,指令會顯示警告,建議使用 srcsetsizes 屬性。

    4. 圖片密度:如果您嘗試在 srcset 中加入圖片,而圖片的像素密度超過 3x,指令就會擲回錯誤。一般來說,我們不建議使用高於 2x 的描述符,因為這會導致意外後果,迫使高解析度行動裝置下載巨大圖片。此外,人眼其實無法分辨 2 倍以上的差異

挑戰

在設計 NgOptimizedImage 時,主要的挑戰是如何將圖片最佳化策略調整為在用戶端架構中運作。Next.js 的預設轉譯體驗是伺服器端轉譯 (SSR) 或靜態網站產生 (SSG),而 Angular 則是用戶端轉譯 (CSR)。雖然 Angular 支援 SSR 程式庫 (angular/universal),但大多數 Angular 應用程式 (約 60%) 都使用 CSR。

圖片指令完全是為了 CSR 而建構,以符合 Angular 應用程式中的一般用途。這項設定會帶來額外限制,因此團隊必須重新思考如何為 CSR 應用程式建立特定最佳化方式。

遇到的部分挑戰如下:

  1. 支援資源提示

    預先載入重要素材資源可協助瀏覽器提早發現這些素材資源。不過,在 Angular 應用程式中加入資源提示相當複雜,原因如下:

    手動新增:開發人員很難手動新增 preload 資源提示。Angular 會為整個專案或網站中的所有路徑使用一個共用的 index.html 檔案。因此,每個路徑的文件 <head> 都相同 (至少在放送時間)。將任何 preload 提示新增至 <head>,表示即使不需要,所有路徑都會預先載入資源。因此,我們不建議手動新增 preload 提示。

    在轉譯期間自動新增:在 CSR 應用程式中,在轉譯期間使用架構在文件標頭新增預先載入提示並無幫助。由於轉譯作業會在下載及執行 JavaScript 後才執行,因此 <head> 會在太晚的時間才轉譯,因此不會有任何價值。

    對於第一個版本的指令,preconnect 提示和 fetchpriority 提示的組合可用於將圖片優先顯示,而非 preload。不過,Aurora 目前正與 Angular CLI 團隊合作,以便在建構期間自動插入資源提示。敬請期待!

  2. 在伺服器上最佳化圖片大小和格式

    由於 Angular 應用程式通常會在用戶端進行轉譯,因此無法在要求時壓縮檔案系統中的圖片,且會原封不動地提供。基於這個原因,建議您使用圖片 CDN 壓縮圖片,並視需要將圖片轉換為 WebP 等新式格式或 AVIF。

    雖然指令不會強制使用圖片 CDN,但強烈建議您搭配指令使用圖片 CDN,並透過內建的載入器確保使用正確的設定選項。

影響

以下示範會說明 Angular 圖片指令可為圖片效能帶來的差異。比較兩個網站:

網站 1:使用原生 <img> 元素,搭配透過 Imgix CDN (搭配預設設定選項) 提供的圖片。

第二個網站:針對所有圖片使用 image 指令。並包含指令擲回的警告或錯誤所直接建議的最佳化項目。

膠卷比較:第一個網站使用原生圖片代碼,第二個網站使用 Angular 圖片指令。

該團隊與合作夥伴合作,驗證圖片指令對實際企業 Angular 應用程式的效能影響。

其中一個合作夥伴是 Land's End。我們預期他們的網站會是實際應用程式可能看到的結果的良好測試案例。

在使用圖片指令之前和之後,他們在品質確保環境中進行Lighthouse 實驗室測試。在電腦上,他們的 LCP 中位數從 12.0 秒降至 3.0 秒,LCP 提升了 75%。在行動裝置上,LCP 中位數從 20.2 秒降至 12.0 秒 (改善幅度 40.6%)。

未來路線圖

這只是 Angular 圖片指令設計的第一部分。我們也預計在日後推出許多其他功能,包括:

  • 回應式圖片的支援功能更完善:

    NgOptimizedImage 目前支援使用 srcset,但必須為每張圖片手動提供 srcsetsizes 屬性。日後,指令可自動產生 srcsetsizes 屬性。

  • 自動插入資源提示

    您可以整合 Angular CLI,為重要的 LCP 圖片產生預先連線和預先載入代碼。

  • 支援 Angular SSR

    MVP 版本的設計考量了 Angular CSR 限制,但探索 Angular SSR (angular/universal) 的圖片最佳化解決方案也相當重要。

  • 改善開發人員體驗

    NgOptimizedImage 要求為每張圖片指定 widthheight 屬性。不過,針對每張圖片指定這些屬性可能會讓部分開發人員感到疲累。在下一個版本中,我們可能會改善開發人員的使用體驗,如下所示:

    1. 支援額外的模式 (類似於 Next.js 中的「fill圖片版面配置選項),不必明確定義寬度/高度。
    2. 使用 CLI 整合功能,藉由判斷圖片的實際尺寸,自動設定本機圖片的寬度和高度。

結論

從 14.2.0 版的開發人員預覽版開始,開發人員將可分階段使用 Angular 圖片指令。歡迎試用 NgOptimizedImage,並提供意見回饋!

特別感謝 Katie Hempenius 和 Alex Castle 的貢獻。