使用 Angular Image 指令最佳化圖片

艾瑞克森 (Kara Erickson)
Kara Erickson
索荷尼 (Lena Sohoni)
Lena Sohoni

2022 年 5 月,Aurora 和 Angular 團隊宣布會合作建構 Angular 的圖片指令。該指令最近已在 Angular v14.2 中為開發人員預覽版發布。本文說明新的圖片指令 NgOptimizedImage 如何支援 Angular 的圖片最佳化功能。

背景

圖片是網路使用者體驗中不可或缺的一環,有 99.9% 的網頁產生了一或多張圖片的要求。圖片也是影響頁面權重的最大因素,因為每頁顯示的中位數為 982 KB

由於圖片的數量和大小不斷增加,因此可能會降低網頁效能,並影響網站體驗核心指標指標。在 79.4% 的電腦版網頁上,圖片是 2021 年最大內容繪製 (LCP) 元素。對我們而言,追求最佳化的圖片已成為許多人持續追求的目標。

Aurora 團隊深信運用架構的力量,為常見的開發人員挑戰提供烘焙解決方案。他們首次進入圖片最佳化空間是 Next.js 圖片元件。該公司將這項元件視為測試基礎,判斷要改善圖片最佳化作業的開發人員體驗 (DX),是否能提升更多採用架構的應用程式效能。

來自 Next.js 使用者 Leboncoin 的第一組結果令人振奮。Leboncoin 開始使用 next/image 後,發現 LCP 大幅改善 (從 2.4 秒到 1.7 秒)。隨著 Next.js 來源的後續採用率增加,符合 LCP 閾值,社群中後續採用 next/image 扮演了角色。不久後,其他架構中的類似功能收到要求,其中一個是 Angular

因此,Aurora 諮詢了 Angular 和 Nuxt,以便設計這些架構的圖片元件原型。Nuxt 圖片元件已於去年推出。現在推出 Angular 圖片指令 (NgOptimizedImage),可將圖片最佳化的預設值導入 Angular。

機會

Angular 是現今開發人員使用的頂尖 JavaScript 架構之一。這項工具由 HTTPArchive 在行動裝置上檢索的 5 萬個來源使用,每週在 NPM 下載量將近 3 百萬

過去一年內 Angular 網站的 LCP。

根據網站體驗核心指標的分數,符合「良好」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 年 Web Almanac 指出,只有 12.7% 的行動網頁會使用預先連線提示,只有 22.1% 的行動網頁會使用預先載入提示。

    當圖片標示為優先順序時,image 指令會在兩個前方執行。

    • 這會將圖片的 fetchPriority 設為 "high",讓瀏覽器知道應下載高優先順序的圖片。
    • 在開發模式中,執行階段檢查會確認 preconnect 資源提示已對應至映像檔的來源。

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

    最後,結合自動化與一致性的組合,可確保 LCP 圖片具有 preconnect 提示、fetchpriority 屬性值為 high,而且不會延遲載入。

  3. 熱門映像檔工具的設定最佳化

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

    這個指令可以提供吸引到的開發人員體驗 (DX),來鼓勵使用圖片 CDN (DX),並在應用程式中設定圖片 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。

這個 image 指令專為 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,但我們強烈建議您搭配 指令及其內建載入器使用映像檔,以確保使用正確的設定選項。

影響

以下示範示範 Angular 圖片指令對圖片效能的影響。比較兩個網站:

網站一:使用原生 <img> 元素,其中包含透過 Imgix CDN 提供的圖片 (使用預設設定選項)。

網站二:針對所有圖片使用圖片指令。其中也包含系統直接根據指令所擲回警告或錯誤所建議的最佳化做法。

幻燈片比較:網站一 (含原生圖片標記) 與網站二 (附 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 (角度/通用) 的圖片最佳化解決方案。

  • 改善開發人員體驗

    使用 NgOptimizedImage 時,必須為每張圖片指定 widthheight 屬性。不過,為每張圖片指定這些元素,對部分開發人員可能感到疲乏。在下一個疊代中,您或許可以改善這裡的開發人員體驗:

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

結語

從開發人員預覽版 v14.2.0 開始,Angular 圖片指令將分階段提供給開發人員。試用 NgOptimizedImage並提供意見!

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