建立有效的圖像元件

圖片元件歸納了效能最佳做法,並提供立即可用的圖片最佳化解決方案。

Leena Sohoni
Leena Sohoni
Kara Erickson
Kara Erickson
Alex Castle
Alex Castle

圖片是網頁應用程式效能瓶頸的常見來源,也是最佳化的重點領域。未經最佳化的圖片會造成頁面過大,目前在第 90「第 90 個」百分位數,佔網頁總權重的 70% 以上。提供多種將圖片最佳化的方法,對智慧型「圖片元件」的要求,並預設具備效能解決方案。

Aurora 團隊與 Next.js 合作建構這類元件。我們的目標是建立最佳化的圖片範本,讓網頁程式開發人員進一步自訂內容。這個元件可做為優質模型,同時為圖片元件設定標準,用於其他架構、內容管理系統 (CMS) 和技術堆疊。我們為 Nutx.js 也提供了類似的元件,並將於日後版本中與 Angular 合作進行圖片最佳化。這篇文章討論了我們如何設計 Next.js 圖片元件,以及我們在過程中學到的經驗。

以圖片元件做為圖片額外資訊

圖片最佳化問題和商機

圖片不僅會影響效能,也會影響業務。網頁的圖片數量是網站訪客第二的重要轉換預測指標。相較於未完成轉換的工作階段,使用者完成轉換的工作階段的圖片少了 38%。Lighthouse 列出多種機會,可透過稽核程序將圖片最佳化,並提升網站體驗指標。以下是一些可能影響網站體驗核心指標和使用者體驗的常見領域:

未設定大小的圖片會對 CLS 造成傷害

如果圖片並未指定大小,可能會導致版面配置不穩定,造成高累計版面配置位移 (CLS)。在 img 元素上設定 widthheight 屬性,有助於避免版面配置位移。例如:

<img src="flower.jpg" width="360" height="240">

應設定寬度和高度,讓算繪後的圖片顯示比例接近原始的長寬比。如果長寬比差異,可能會導致圖片變形。您可以透過這個相對較新的屬性,在 CSS 中指定長寬比,這樣就能在防範 CLS 的情況下,配合調整圖片大小。

大型圖片可能會對 LCP 造成負面影響

圖片檔案越大,下載所需時間就越長。大型圖片可以是網頁的「主要內容」圖片,或是可觸發最大內容繪製 (LCP) 的可視區域中最重要的元素。如果圖片屬於重要內容,但下載時間過長,LCP 就會延遲。

在許多情況下,開發人員可以透過更好的壓縮功能和回應式圖片來縮減圖片大小。<img> 元素的 srcsetsizes 屬性可協助您提供不同大小的圖片檔。這樣一來,瀏覽器就能根據螢幕大小和解析度,選擇適合的選項。

圖片壓縮效果不佳可能會導致 LCP 受損

與常用的 JPEG 和 PNG 格式相比,新型圖片格式 (例如 AVIFWebP) 的壓縮效果較佳。改善壓縮功能 (在某些情況下可將檔案大小縮減 25% 至 50%),以維持相同的圖片品質。降低下載速度可加快下載速度,並減少數據用量。應用程式應放送新型圖片格式給支援這些格式的瀏覽器。

載入不必要的圖片會對 LCP 造成負面影響

網頁載入時,使用者不會看到需捲動位置或不在可視區域內的圖片。並延後不參與 LCP 並延遲。之後使用者將畫面捲動至圖片時,就能使用延遲載入功能載入這類圖片。

最佳化方面的挑戰

團隊可評估先前所列問題造成的績效成本,並採取最佳做法解決方案來克服這些問題。不過,這種情況通常在實務上不會發生,效率低落的圖片也會持續減緩網頁速度。可能原因如下:

  • 優先順序:網頁開發人員通常專注於程式碼、JavaScript 和資料最佳化。因此,他們可能不知道圖片相關問題,或找出最佳化方法。由設計人員或使用者上傳的圖片在優先順序清單中可能不高。
  • 立即可用的解決方案:即使開發人員瞭解圖片最佳化的細微差異,如果架構或技術堆疊沒有一體適用的解決方案,可能仍是艱鉅的任務。
  • 動態圖片:除了應用程式的靜態圖片外,動態圖片也是由使用者上傳,或從外部資料庫/ CMS 取得。指定這類圖片來源的尺寸並不容易。
  • 標記超載:如果要的解決方案包括加入圖片大小或使用 srcset 來呈現不同尺寸的圖片,則必須為每張圖片加上額外標記,但實際過程可能相當繁瑣。srcset 屬性於 2014 年推出,但現今只有 26.5%的網站使用這項屬性。使用 srcset 時,開發人員必須製作各種大小的圖片。just-gimme-an-img 這類工具可提供說明,但每張圖片都必須手動使用。
  • 瀏覽器支援:AVIF 和 WebP 等新型圖片格式可建立較小的圖片檔,但需要對不支援這類檔案的瀏覽器進行特殊處理。開發人員必須採用內容協商<picture> 元素等策略,才能在所有瀏覽器中顯示圖片。
  • 延遲載入小工具:您可以運用多種技術和程式庫,實作需捲動位置圖片的延遲載入功能。挑選出最好的那份是一件簡單的事,開發人員也可能沒有知道載入延遲圖片的最佳距離。裝置上的可視區域大小不同,這項差異可能會更複雜。
  • 不斷變動的環境:瀏覽器開始支援新的 HTML 或 CSS 功能來提升成效,因此開發人員很難評估各項功能。舉例來說,Chrome 推出了擷取優先順序功能做為來源試用。可用來提高網頁上特定圖片的優先順序。整體而言,如果開發人員在元件層級評估及實作這類強化措施,會更加容易。

使用圖片元件做為解決方案

無論是要改進圖片,還是針對個別應用程式實作圖片的難題,我們都洞悉了圖片元件的概念。圖片元件可以封裝並強制執行最佳做法。將 <img> 元素替換為圖片元件,可讓開發人員更有效地解決圖片效能不佳的問題。

過去一年來,我們與 Next.js 架構合作,設計並implement圖片元件。這可以做為 Next.js 應用程式中現有 <img> 元素的直接取代,如下所示。

// Before with <img> element:
function Logo() {
  return <img src="/logo.jpg" alt="logo" height="200" width="100" />
}

// After with image component:
import Image from 'next/image'

function Logo() {
  return <Image src="/logo.jpg" alt="logo" height="200" width="100" />
}

這項元件會運用豐富的功能與原則,盡量解決圖片相關問題。同時也提供多種選項,讓開發人員可根據各種圖片需求自訂圖片。

防止版面配置位移

如先前所述,未調整大小的圖片會導致版面配置位移,造成 CLS 的影響。使用 Next.js 圖片元件時,開發人員必須使用 widthheight 屬性提供圖片大小,以避免任何版面配置位移。如果大小不明,開發人員必須指定 layout=fill,才能放送大小未超過容器大小的圖片。或者,您也可以使用靜態圖片匯入功能,在建構期間擷取硬碟中的實際圖片大小,並將圖片加入映像檔中。

// Image component with width and height specified
<Image src="/logo.jpg" alt="logo" height="200" width="100" />

// Image component with layout specified
<Image src="/hero.jpg" layout="fill" objectFit="cover" alt="hero" />

// Image component with image import
import Image from 'next/image'
import logo from './logo.png'

function Logo() {
  return <Image src={logo} alt="logo" />
}

由於開發人員無法使用未調整大小的圖片元件,因此設計可確保開發人員花時間考量圖片大小,以及避免版面配置位移變動。

加快回應速度

如要讓圖片在各種裝置上都能回應,開發人員必須在 <img> 元素中設定 srcsetsizes 屬性。我們希望減少這個圖片元件的負擔。我們將 Next.js 圖片元件的設計為每個應用程式僅設定一次屬性值。我們會根據版面配置模式,將這些內容套用至圖片元件的所有執行個體。我們擬出了三部分的解決方案:

  1. deviceSizes 屬性:這個屬性可用來根據應用程式使用者常見的裝置,設定一次性的中斷點。中斷點的預設值包含在設定檔中。
  2. imageSizes 屬性:這是可設定的屬性,可用於取得與裝置大小中斷點對應的圖片大小。
  3. 每張圖片中的 layout 屬性:這項設定用於指出每張圖片的 deviceSizesimageSizes 屬性的使用方式。版面配置模式支援的值為 fixedfillintrinsicresponsive

當圖片模式以「回應式」或「填入」模式要求時,Next.js 會根據要求網頁的裝置大小,識別要提供的圖片,並在圖片中適當設定 srcsetsizes

以下比較圖說明如何使用版面配置模式,控制不同螢幕上的圖片尺寸。我們已在 Next.js 文件中使用共用的示範圖片,這些圖片都用手機和標準筆記型電腦瀏覽。

筆電螢幕 手機螢幕
版面配置 = 內建函式:配合小型檢視點的容器寬度縮小。不會在較大的檢視點上放大至圖片內建函式的大小。容器寬度為 100%
山岳圖片的顯示方式 已縮小山脈圖片
Layout = 固定:圖片沒有回應式。無論在何種裝置算繪裝置,寬度和高度都固定類似於「」元素。
山岳圖片的顯示方式 顯示為與螢幕不符的山岳影像
版面配置 = 回應式:根據容器在不同可視區域的寬度,縮小或放大,維持顯示比例。
已調整為符合螢幕大小的山岳圖片 根據螢幕縮小的山脈圖片
Layout = Fill:為填滿父項容器的寬度和高度。(父項 `
在本範例中,「寬度」設為 300*500)
經轉譯為 300*500 大小的山岳圖片 經轉譯為 300*500 大小的山岳圖片
配合不同版面配置轉譯的圖片

提供內建延遲載入功能

圖片元件提供內建的高效能延遲載入解決方案。使用 <img> 元素時,一些延遲載入的原生選項都有,但這些選項都有缺點,因此難以使用。開發人員可能會採用下列其中一種延遲載入方法:

  • 指定 loading 屬性:這項功能易於導入,但部分瀏覽器目前不支援這項屬性。
  • 使用 Intersection Observer API:如要建立自訂延遲載入解決方案,您必須耗費心力和周全的設計與實作。開發人員不一定隨時準備好處理這項作業。
  • 匯入第三方程式庫以延遲載入圖片:為延遲載入功能評估及整合適當的第三方程式庫時,可能需要花費額外的心力。

在 Next.js 圖片元件中,載入功能預設為 "lazy"。延遲載入是使用 Intersection Observer 實作,這個指標適用於大部分新式瀏覽器。開發人員不需要採取額外行動即可啟用,但可視需要停用。

預先載入重要圖片

LCP 元素通常都是圖片,而大型圖片可能會延遲 LCP。建議您預先載入重要圖片,加快瀏覽器探索圖片的速度。使用 <img> 元素時,您可以在 HTML 標頭中加入預先載入提示,如下所示。

<link rel="preload" as="image" href="important.png">

無論採用的架構為何,設計良好的圖片元件都應提供調整圖片載入序列的方式。如果是 Next.js 圖片元件,開發人員可以使用圖片元件的 priority 屬性來指出適合預先載入的圖片。

<Image src="/hero.jpg" alt="hero" height="400" width="200" priority />

新增 priority 屬性可簡化標記,而且使用起來更加便利。圖片元件開發人員也可以嘗試運用經驗法則,針對網頁上符合特定條件的不需捲動位置圖片自動預先載入。

鼓勵採用高效能的圖片託管技術

建議您使用 Image CDN 來自動進行圖片最佳化作業,而且也支援 WebP 和 AVIF 等新型圖片格式。根據預設,Next.js 圖片元件會使用載入器架構使用圖片 CDN。以下範例顯示載入器允許在 Next.js 設定檔中設定 CDN。

module.exports = {
  images: {
    loader: 'imgix',
    path: 'https://ImgApp/imgix.net',
  },
}

透過這項設定,開發人員便可在圖片來源中使用相對網址,而架構會將相對網址與 CDN 路徑串連,以產生絕對網址。系統支援 ImgixCloudinaryAkamai 等熱門映像檔 CDN。該架構支援為應用程式實作自訂 loader 函式,以便使用自訂雲端服務供應商。

支援自行代管的圖片

有些網站可能無法使用圖片 CDN。在這種情況下,圖片元件必須支援自行代管的圖片。Next.js 圖片元件使用圖片最佳化工具做為內建圖片伺服器,可提供 CDN 類 API。如果已在伺服器上安裝最佳化工具,就會使用 Sharp 進行實際工作環境圖片轉換。想要建構自己的圖片最佳化管道的使用者,這個程式庫是絕佳選擇。

支援漸進式載入

「漸進式載入」是一種技術,可在實際圖片載入時,顯示預留位置圖片 (品質通常大幅降低) 以維持使用者興趣。它可以改善感知效能,並改善使用者體驗。這可以與延遲載入搭配使用,以顯示需捲動位置的圖片或不需捲動位置的圖片。

Next.js 圖片元件可透過 placeholder 屬性支援漸進式載入圖片。這可做為 LQIP (低畫質圖片預留位置),在實際載入圖片時,顯示低畫質或經過模糊處理的圖片。

影響

導入上述所有最佳化功能後,我們在實際工作環境中的 Next.js Image 元件大獲成功,同時也與其他技術堆疊合作處理類似的圖片元件。

Leboncoin 將舊版 JavaScript 前端遷移至 Next.js 後,也升級映像檔管道,以便使用 Next.js Image 元件。網頁從 <img> 遷移至下一個/圖片後,LCP 從 2.4 秒降至 1.7 秒。網頁下載的圖片位元組總數已從 663 kB 增加至 326kB (延遲載入的圖片位元組約 100 KB)。

汲取的經驗教訓

任何建立 Next.js 應用程式的使用者,都可透過 Next.js 圖片元件進行最佳化。不過,如果您想為其他架構或 CMS 建構類似的效能抽象化機制,請參考我們先前學到的教訓,或許會有幫助。

安全閥會造成更嚴重的傷害

在 Next.js 圖片元件的早期版本中,我們提供了 unsized 屬性,可讓開發人員略過大小規定,並使用未指定尺寸的圖片。我們認為在必須事先知道圖片高度或寬度的情況下,才需要使用這項資訊。不過,我們注意到使用者建議將 GitHub 問題中的 unsized 屬性做為全面性的解決方案,藉此解決大小需求相關問題,即使這類問題都能以不會使 CLS 惡劣的方式解決問題也一樣。隨後我們已淘汰並移除 unsized 屬性。

區分有用的阻礙與流暢的惱人

規定圖片大小的規定為「實用的摩擦力」。限制元件的使用方式,但讓使用者以換取優異的效能優勢。如果使用者能清楚瞭解可能提升的成效優勢,便可立即接受限制。因此,建議您透過與這個元件相關的說明文件和其他已發布的素材,說明這項取捨。

不過,你可以找到處理這類阻礙的解決方法,同時又不會犧牲效能。舉例來說,在開發 Next.js 圖片元件時,我們收到許多抱怨查詢本機儲存圖片尺寸很煩人。我們新增了靜態圖片匯入功能,並在建構期間使用 Babel 外掛程式自動擷取本機圖片的尺寸,簡化這項程序。

在便利功能和效能最佳化之間取得平衡

如果圖片元件沒有任何作用,而是對使用者造成「實用的不便」,開發人員通常不希望使用此元件。我們發現,雖然圖片大小及自動產生 srcset 值等效能功能最為重要,為開發人員提供的便利功能 (例如自動延遲載入和內建模糊的預留位置),也引起了 Next.js Image 元件的興趣。

制定功能藍圖,提升採用率

要打造適合各種情況的解決方案,實在困難。您可能會想為 75% 的使用者設計一個良好的產品,然後再告訴另外 25% 他們「在這些情況下,這個元件並不適合您」。

實務上,這項策略與元件設計人員的目標不符。您希望開發人員採用元件,以便從效能獲得優勢中獲益。如果現有使用者無法遷移,且已離開對話,這種情況並不容易。他們可能會表現出失望,導致對採用率產生負面看法。

建議您為元件準備一份藍圖,以長期涵蓋所有合理用途。並在說明文件中清楚說明您的系統並未支援的項目和原因,以便清楚說明元件設計問題。

結論

圖片的使用和最佳化相當複雜。開發人員必須兼顧圖片效能和品質,同時確保提供優質的使用者體驗。這使得圖片最佳化作業具備高價值、高影響力的工作。

我們不必每次都要重新建構應用程式,而是設計出一個最佳做法範本,開發人員、架構和其他技術人員可以參考範本,做為實作項目。我們支援其他架構的圖片元件,因此這種體驗確實能發揮效益。

Next.js 圖片元件已順利改善 Next.js 應用程式的效能,進而改善使用者體驗。我們相信這個模型在更廣大的生態系統中能有效運作,也歡迎開發人員表示願意在專案中採用這個模型。