Web圖像組件設計的優秀實踐
大家好,我是 ConardLi ,網頁中的圖片處理一直是 Web 開發的一大挑戰,今天跟大家來一起看看 Next.js 中的 Image 組件,我覺得這個組件的設計有很多值得借鑒的地方,可以作為圖片組件設計的優秀實踐。英文原文在這:https://web.dev/image-component/
本文中會涉及一些網頁性能指標,沒有了解過的同學可以先看一下我這篇文章:
網頁中的圖像帶來的主要問題和優化方向
網頁中的圖片不僅會影響網頁性能,還有可能會影響業務,一個網頁中加載的圖片數量是用戶訪問網站的轉化率的第二大影響因素。
作為網頁最佳實踐檢查中的的一部分, Lighthouse 列出了很多種優化圖片加載的建議,比如下面這幾點:
未指定大小的圖片會降低 CLS
未指定寬高的圖片會導致布局的不穩定并導致布局偏移指標 ( CLS ) 惡化。在 img 元素上設置 width 和 height 屬性可以優化這個問題,例如:
- <img src="flower.jpg" width="360" height="240">
寬度和高度應該設置的更接近圖片本身的寬高比。如果差的太多可能導致圖像看起來失真。
使用 CSS 新增的 aspect-ratio 屬性可以幫你更好的響應式的調整圖片大小。
圖片太大可能影響 LCP
圖像的文件大小越大,下載所需的時間就越長。網頁中的大圖可能是觸發最大內容繪制指標 ( LCP )的最重要元素。作為網頁關鍵內容的一部分并且需要很長時間下載的圖片肯定會降低網頁的 LCP 。
在很多情況下,開發者可以通過更好的壓縮或者使用響應式圖像來減小圖片大小。 <img> 元素的 srcset 和 sizes 屬性可以指定不同大小的圖片文件。然后瀏覽器可以根據屏幕大小和分辨率選擇性加載。
糟糕的圖像壓縮可能影響 LCP
AVIF 或 WebP 等現代圖片格式可以提供比 JPEG 和 PNG 等常用格式更好的壓縮能力。在某些情況下,對于相同質量的圖片,更好的壓縮可以將文件大小減少 25% 到 50% 。這種體積上的減少可以讓下載速度更快,數據消耗更少。
加載不必要的圖片可能影響 LCP
加載網頁時,用戶在首屏看不到的圖片可以延遲加載,這樣它們就不會對 LCP 造成影響。
圖片優化的主要挑戰
在上面我們已經把主要問題和優化方向都列出來了,事實上,由于一些問題,并不是所有的網站都能作出這些優化,比如:
優先事項:Web 開發者可能通常更傾向于關注代碼、JavaScript和數據優化。大部分前端可能不知道圖片的主要問題以及如何優化它們。開箱即用的解決方案:即使我們意識到了這些問題,但是對于我們的研發框架可能缺少一些開箱即用的解決方案,這會大大提升優化成本。動態加載圖片:除了我們開發的時候引入的一些圖片,可能還有一部分是來自于用戶上傳。在圖片來源是動態的情況下,定義此類圖片的大小可能比較困難。
- 瀏覽器支持
- AVIF
- WebP
懶加載的復雜性 :實現懶加載有很多鐘方法,那你至少哪種方法是最適合你的網頁的嗎,不同設備上不同的視口尺寸也會將問題復雜化。Image組件的最佳實踐
在過去的一年里,我們使用 Next.js 框架設計和實現了 Image組件 。它可以替換 Next.js 中的 <img> 元素,這是一個使用示例:
- // Before with <img> element:
- function Logo() {
- return <img src="/code秘密花園.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 Image 組件時,開發者必須使用 width 和 height 屬性指定圖片大小,以防止任何布局偏移。如果大小未知,開發者必須指定 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 './code秘密花園.png'
- function Logo() {
- return <Image src={logo} alt="logo" />
- }
響應式
要使圖像跨設備自適應,開發者必須在 <img> 元素中設置 srcset 和 sizes 屬性。如果使用 Image 組件就可以不用做這項工作。 Next.js 中的 Image 組件可以有一個全局的圖片設置,根據布局模式可以將它們應用于 Image 組件的所有實例,有下面三個屬性:
deviceSizes屬性:此屬性可用于基于應用程序用戶基礎的通用設備一次性配置斷點。imageSizes property:這也是一個可配置的屬性,用于獲取與設備大小斷點對應的圖像大小。
- layout
- deviceSizes
- imageSizes
- fixed,fill,intrinsic
- responsive
當使用 fill 或 responsive 布局模式加載圖片時, Next.js 會根據請求頁面的設備的大小識別要提供的圖片,并適當地設置 srcset 和 sizes 。
下面的例子展示了怎么使用布局模式來控制不同屏幕上的圖像大小。
Layout = Intrinsic :縮小以適應容器在較小視口上的寬度。在較大的視口上放大時不會超過圖像的固有尺寸,容器寬度為 100%
Layout = Fixed :不管在什么設備上,寬度和高度是固定的。
Layout = Responsive :根據容器在不同視口上的寬度縮小或放大,保持寬高比。
Layout = Fill :寬高自動填充父容器
懶加載
Image 組件默認提供了一個內置的、高性能的延遲加載解決方案。 <img> 元素有一些默認的懶加載方案,但它們都有很多缺點,使用起來也比較麻煩,我們可能會采用以下懶加載方法之一:
- 指定
loading屬性:實現簡單,但兼容性差 - 使用
Intersection Observer API:設計一個自定義的懶加載解決方案需要深思熟慮的設計和實現,不是所有開發都有時間和精力做這種設計。 -
第三方懶加載庫:你需要一定的時間對這些庫進行選擇和評估。
在 Next.js 的 Image 組件中,圖片默認的設置就是 Lazy 的。懶加載是使用 Intersection Observer 實現的,它的兼容性很好。我們不需要做任何額外的事情來啟用它,但我們可以根據具體的場景去選擇禁用。
預加載
上面提到了,圖像的文件大小越大,下載所需的時間就越長。網頁中的大圖可能是觸發最大內容繪制指標 ( LCP )的最重要元素,對一些大圖進行預加載可能是個好主意。
使用 <img> 元素時, HTML 標題中可能包含預加載提示:
- <link rel="preload" as="image" href="important.png">
不管使用什么框架,一個設計良好的圖像組件應該提供一種方法來調整圖像的加載順序。在 Next.js 的 Image 組件中,開發人員可以使用 priority 屬性指示適合預加載的圖像。
- <Image src="/code秘密花園.jpg" alt="ConardLi" height="400" width="200" priority />
推薦CDN托管圖片
Next.js 的 Image 默認使用一種加載器架構來處理圖片,你可以自定義配置圖片的 CDN 前綴。
- module.exports = {
- images: {
- loader: 'imgix',
- path: 'https://ImgApp/imgix.net',
- },
- }
通過這種配置,開發者可以在圖片加載時中使用相對路徑,框架會將相對路徑與 CDN 路徑連接起來生成絕對 URL 。目前支持一些主流的圖像 CDN ,如 Imgix、Cloudinary 和 Akamai 。這種架構通過 loader 為應用支持使用自定義 CDN 提供商。
漸進式加載
所謂漸進式加載,就是在實際圖像加載時先顯示質量較差的占位符圖,它可以與懶加載結合使用,從而提高了感知性能并增強用戶體驗。
Next.js Image 組件支持通過 placeholder 屬性對圖像進行漸進式加載,用于在加載實際圖像時顯示低質量或模糊的圖像。
效果
下面是 leboncoin 使用了 Image 組件后的優化效果:
LCP 從 2.4s 下降到 1.7s ,為頁面下載的總圖像資源大小從 663kB 增加到了 326kB (懶加載的圖片大小約為 100kB )。


































