天天看點

如何通過響應式圖檔加快網頁加載速度

作者:前端達人
轉載說明:原創不易,未經授權,謝絕任何形式的轉載

開篇

確定圖檔在所有螢幕尺寸上都能良好顯示是一項困難的任務,因為你需要考慮圖檔的大小、圖檔的放置位置、顯示圖檔的比例、使用者連接配接的速度等等衆多因素。結果是,大多數開發者隻會為所有螢幕尺寸使用同一張圖檔,并讓浏覽器調整圖檔的大小以适應螢幕。這是一種不好的做法,因為浏覽器仍會下載下傳完整尺寸的圖檔(通常非常大),即使它隻以其一部分尺寸顯示。這會浪費使用者的帶寬,并且會顯著減慢頁面加載速度(尤其是在較慢的連接配接下)。

解決這個問題的方法是使用響應式圖檔。響應式圖檔是根據使用者的螢幕尺寸進行優化的圖檔。這意味着圖檔将以适合使用者裝置的正确尺寸和品質進行下載下傳。這将顯著減少傳輸給使用者的資料量,加快頁面加載速度。有許多實作響應式圖檔的方法,從簡單到複雜。在本文中,我将向您展示如何在您的網站上呈現響應式圖檔的所有方式。

img srcset 屬性

到目前為止,實作響應式圖檔最簡單的方法是在img标簽上使用srcset屬性。該屬性允許您定義多個不同尺寸的圖檔,然後浏覽器将自動選擇最适合使用者螢幕尺寸的圖檔。

<img
  src="tree-1200.jpg"
  alt="A tree"
  srcset="tree-400.jpg 400w, tree-800.jpg 800w, tree-1200.jpg 1200w"
/>           

這段代碼可能看起來有些混亂,是以讓我詳細解釋一下其中發生的事情。首先,我們有了您已經熟悉的普通src和alt屬性,它們與所有圖檔一樣。在極少數情況下,如果使用者使用的浏覽器不支援srcset,那麼将使用src URL來顯示圖檔。不過,這種情況非常罕見,因為srcset在所有主要浏覽器中已經支援了5-10年。

讓人困惑的是srcset屬性。該屬性接受一個逗号分隔的圖檔URL和它們的寬度清單。如果我們看一下清單中的第一項tree-400.jpg 400w,可以看到URL是tree-400.jpg。這個URL的名稱并不重要,但通常當您在不同尺寸上有多個相同的圖檔時,您會希望在名稱中加上尺寸資訊。

這項内容的第二部分是400w。這可能會讓人困惑,因為w不是CSS機關,實際上w代表圖像的實際寬度,以像素為機關。您可以通過在檔案浏覽器/資料總管中檢查圖像來輕松找到這個寬度。如果您使用的是Windows作業系統,可以右鍵單擊圖像,選擇屬性,而在Mac上應該有一個名為"擷取資訊"的選項。在本例中,圖像的寬度為400像素,是以我們将寬度設定為400w。

浏覽器将使用這些資訊來自動确定要下載下傳的圖檔。例如,如果使用者的螢幕寬度小于400像素,它将使用tree-400.jpg圖像,因為這是可以在不進行任何拉伸/模糊像素的情況下使用的最小圖像。一旦浏覽器的寬度大于400像素,浏覽器将切換到使用tree-800.jpg圖像。這是因為400像素的圖像現在比目前螢幕尺寸小,如果使用它會被拉伸/模糊。對于所有螢幕尺寸,這個過程會一直持續,直到浏覽器達到清單中最大的圖像。

這很棒,因為現在在小螢幕上,浏覽器将下載下傳一個較小的圖像,而大螢幕仍将獲得高分辨率的圖像。這将顯著減少傳輸給使用者的資料量,并加快頁面加載速度。下面是一個示例,展示了這種情況。嘗試将浏覽器大小調整為較小的尺寸,然後重新加載頁面,您将看到下載下傳了較小的圖像。

<img
  style="width: 100%; border-radius: 1rem;"
  src="https://placehold.co/3200x800/png"
  srcset="
    https://placehold.co/800x200/png   800w,
    https://placehold.co/1600x400/png 1600w,
    https://placehold.co/3200x800/png 3200w
  "
/>           
如何通過響應式圖檔加快網頁加載速度
在進行測試時,您可能會注意到下載下傳的圖像實際上比您預期的要大。例如,如果您的螢幕寬度為700像素,您的浏覽器可能仍會下載下傳1600像素寬的圖像,而不是800像素寬的圖像。這是因為浏覽器還考慮了您裝置的像素密度。如果您使用的是高分辨率裝置或浏覽器縮放級别較高,浏覽器将下載下傳一個較大的圖像,以確定在您的螢幕上顯示良好,因為每個CSS像素實際上對應螢幕上的多個像素。要檢查裝置的像素密度,您可以在控制台中使用window.devicePixelRatio。

如何處理不同的像素密度

有時候,您可能有一張圖像在螢幕上始終保持相同的尺寸,但您希望它在高分辨率裝置上看起來很好。例如,如果您的标志始終為100像素寬,在隻提供100像素寬圖像的情況下,在高分辨率裝置上會顯得模糊不清。為了解決這個問題,您可以使用srcset屬性,通過使用x機關來表示像素密度來提供多個不同尺寸的圖像。

<img
  src="logo-200.jpg"
  alt="Our Logo"
  srcset="logo-100.jpg 1x, logo-150.jpg 1.5x, logo-200.jpg 2x"
/>           

上述代碼與我們之前的srcset示例非常相似,但主要差別在于我們使用了類似1.5x和2x的機關,而不是寫死的像素值。這些機關指的是螢幕的像素密度。例如,如果某人的螢幕具有每個CSS像素1.25個裝置像素的像素密度,則将使用logo-150.jpg圖像,因為這是可以在不拉伸/模糊像素的情況下使用的最小圖像。

您無需包含1x機關,因為它是預設值。如果您隻有兩個圖像,您可以使用logo-100.jpg,logo-200.jpg 2x,而不是logo-100.jpg 1x,logo-200.jpg 2x。

img sizes 屬性

到目前為止,我們介紹的是實作響應式圖檔的最基本方法,但在許多情況下,您的圖像尺寸實際上并不等于螢幕的寬度。本部落格就是一個很好的例子。在小螢幕上,我的部落格内容(包括圖像)占據了整個螢幕的寬度,但在較大螢幕上,我将内容居中顯示,并設定了一個有限的最大寬度。如果我們僅使用像上面那樣的srcset,我們的圖像将根據浏覽器視窗的完整尺寸進行縮放,這将導緻在大螢幕上圖像比實際需要的要大。這就是sizes屬性的用途。

sizes屬性允許您定義圖像的單個尺寸,例如50vw,或者一組媒體查詢,用于确定圖像應該使用的尺寸。預設情況下,如果您沒有将sizes屬性添加到img标簽中,它會假定尺寸為100vw,這就是為什麼上面的圖像根據浏覽器視窗的完整寬度進行縮放。讓我們看一下如何使用sizes屬性來考慮具有最大尺寸的部落格這樣的情況。

<img
  src="tree-1200.jpg"
  alt="A tree"
  srcset="tree-400.jpg 400w, tree-800.jpg 800w, tree-1200.jpg 1200w"
  sizes="(max-width: 800px) 100vw, 800px"
/>           

上面的代碼與之前的代碼完全相同,隻是我們添加了sizes屬性。sizes屬性接受一個以逗号分隔的媒體查詢和尺寸清單。為了了解其中的内容,讓我們逐個解析清單中的每個項。

我們的第一個項(max-width: 800px)100vw 有兩個部分。第一部分是我們要檢查的媒體查詢。在這種情況下,我們要檢查螢幕寬度是否小于800像素。第二部分是如果媒體查詢為true時我們要使用的尺寸。在這種情況下,我們使用100vw,這意味着我們希望浏覽器根據浏覽器視窗的完整寬度選擇圖像尺寸。

第二個項800px沒有媒體查詢,而隻是一個尺寸。這被視為我們的回退尺寸。如果之前定義的所有媒體查詢都為false,那麼它将使用這個回退尺寸。從本質上講,您可以将其視為始終為true的媒體查詢。我們通過這個項表達的意思是,假設我們的圖像在螢幕上占據了800像素,我們應該選擇我們的圖像。然後,浏覽器将使用這個尺寸來确定要下載下傳的圖像。如果您的浏覽器具有高分辨率或您在頁面上進行了縮放,它可能會下載下傳比800像素更大的圖像,但通常情況下,這是確定圖像不會過大的一種好方法。

将這兩個項組合起來,基本上是在說我們的圖像應該根據浏覽器的寬度選擇,在800像素之前。在那一點上,圖像在我們的螢幕上永遠不會占用超過800像素的空間,是以我們應該根據這個800像素的尺寸來調整我們的圖像尺寸。這是我為這個部落格添加響應式圖像的代碼方式,因為我的部落格在較大的螢幕尺寸上受到最大寬度的限制。讓我們看一個實際的示例。

<img
  style="width: 100%; border-radius: 1rem;"
  src="https://placehold.co/3200x800/png"
  srcset="
    https://placehold.co/400x100/png   400w,
    https://placehold.co/800x200/png   800w,
    https://placehold.co/1200x300/png 1200w,
    https://placehold.co/1600x400/png 1600w,
    https://placehold.co/3200x800/png 3200w
  "
  sizes="(max-width: 800px) 100vw, 800px"
/>           
如何通過響應式圖檔加快網頁加載速度

我添加了許多不同的圖像尺寸,這樣您就可以看到它們如何與不同的像素密度配合工作。如果您使用的是高分辨率裝置,您可能會注意到浏覽器下載下傳了比800像素更大的圖像。您還可以通過縮放裝置來模拟此過程,因為您的裝置縮放得越多,像素密度就越高,如果您縮放足夠多,浏覽器将需要下載下傳更高分辨率的圖像,以確定在螢幕上顯示良好。

潛在的陷阱

sizes屬性非常強大,但在使用它時需要注意以下幾點。

順序很重要

如果您的sizes屬性中有多個媒體查詢,将選擇第一個為true的媒體查詢對應的圖像。這意味着您的媒體查詢的順序很重要。

<img
  src="https://placehold.co/3200x800/png"
  srcset="
    https://placehold.co/400x100/png 400w,
    https://placehold.co/800x200/png 800w
  "
  sizes="(max-width: 800px) 100vw, (max-width: 500px) 50vw, 1200px"
/>           

如果您按照上述的方式編寫sizes屬性,那麼您的代碼将無法按預期工作。原因是第一個媒體查詢(max-width: 800px)100vw 在所有小于800像素的螢幕尺寸下都為真。這意味着第二個媒體查詢(max-width: 500px)50vw 将永遠不會被使用,因為隻有在螢幕小于500像素時才為真,而在這些尺寸範圍内第一個媒體查詢将始終為真,是以它将始終被優先選擇。為了解決這個問題,您需要重新排序媒體查詢,使最具體的媒體查詢排在最前面,最不具體的媒體查詢排在最後。

<img
  src="https://placehold.co/3200x800/png"
  srcset="
    https://placehold.co/400x100/png 400w,
    https://placehold.co/800x200/png 800w
  "
  sizes="(max-width: 500px) 50vw, (max-width: 800px) 100vw, 1200px"
/>           

同樣重要的是,確定您的預設尺寸(即沒有媒體查詢的尺寸)始終放在最後,因為它總是為真,是以如果它排在最前面,它将始終被選擇,而不考慮其他媒體查詢。

使用百分比

到目前為止,我已經向您展示了如何使用像px這樣的具體尺寸,以及如何使用基于浏覽器視窗的尺寸,比如vw,但是百分比尺寸(如50%)該怎麼辦呢?不幸的是,在sizes屬性中不支援百分比尺寸。原因是浏覽器在不知道父元素的寬度之前,無法确定百分比定義的内容的寬度。這意味着浏覽器必須等到整個頁面加載完成後才能确定要下載下傳哪個圖像。這将是一個糟糕的使用者體驗,因為使用者必須等到整個頁面加載完成才能看到任何圖像。

picture 元素

到目前為止,我們主要讨論了如何以不同尺寸渲染相同的圖像,以幫助提高加載時間,但這并沒有涵蓋在不同螢幕尺寸下顯示不同圖像的情況。例如,如果您的頁面有一個寬度跨越整個頁面的大标題,您可能希望在移動裝置和桌面裝置上顯示不同的圖像,因為您可以在桌面裝置上使用更多細節的圖像。這就是picture元素的用途。

picture元素允許您定義多個source元素,用于在不同的螢幕尺寸下定義要使用的不同圖像。然後,浏覽器将選擇與目前螢幕尺寸比對的第一個source元素,并使用該圖像。如果沒有任何source元素與目前螢幕尺寸比對,則将使用picture元素中定義的img作為備用圖像。

<picture>
  <source media="(max-width: 500px)" srcset="hiking-narrow.jpg" />
  <img src="hiking-wide.jpg" alt="Someone jumping on a hike" />
</picture>           
如何通過響應式圖檔加快網頁加載速度

如果你調整浏覽器的大小,你應該會看到圖像在兩個不同版本之間變化。如果你使用的是移動裝置,你可能需要縮放來觀察圖像的變化。我們為較小的螢幕尺寸提供了更裁剪的圖像版本,因為在較小的螢幕上,圖像的焦點——人物——會變得太小。

現在讓我們看一下實際的代碼,了解它是如何工作的。為了讓picture元素起作用,你至少需要将一個普通的img标簽放在picture元素的最後。

<picture>
  <img src="hiking-wide.jpg" alt="Someone jumping on a hike" />
</picture>           

這樣做将隻是像普通的img标簽一樣渲染圖像。在這裡,更加進階的是使用source元素。除了預設版本之外,每個圖像的變體都應該有自己的source元素。在我們的例子中,我們隻有一個source元素,但您可以根據需要添加任意數量的source元素。

<picture>
  <source media="(max-width: 500px)" srcset="hiking-narrow.jpg" />
  <source media="(max-width: 1000px)" srcset="hiking-medium.jpg" />
  <img src="hiking-wide.jpg" alt="Someone jumping on a hike" />
</picture>           

在每個source元素内部,您有兩個主要屬性。srcset屬性的工作方式與img标簽的srcset屬性相同。這意味着,如果我們有hiking-narrow.jpg圖像的多個分辨率,我們可以将它們包含在srcset屬性中。不過,在使用picture元素時,每個source元素通常隻有一個分辨率,是以您可以将其作為srcset屬性中的唯一URL。

另一個屬性是media屬性。它的工作方式類似于sizes屬性中的媒體查詢,但是在source元素的media屬性中,您隻能定義一個媒體查詢。這些查詢與sizes屬性一樣,從上到下逐個檢查,隻有第一個比對的媒體查詢會被使用。如果沒有任何媒體查詢比對,則使用img标簽作為備選項,這也是為什麼我們沒有針對較大螢幕尺寸專門設定source元素的原因。

為什麼要使用picture元素而不是其他替代方案

對于picture元素的一個大誤解是,為什麼要使用它而不是img元素的sizes屬性或CSS。

為什麼 sizes 不适合

sizes屬性不适合此任務的主要原因是,picture元素始終會切換到與目前螢幕尺寸比對的source元素中定義的圖像。這意味着,如果您通過縮放或調整視窗大小來更改螢幕尺寸,它将切換到正确的圖像。

sizes屬性的工作方式類似,但隻适用于增大螢幕尺寸的情況。如果您的螢幕尺寸縮小,浏覽器将不會切換或下載下傳較小的圖像,因為它已經有了較大的圖像,是以将繼續渲染該圖像。這非常好,因為它可以節省帶寬,因為當您已經擁有較大的圖像時,下載下傳較小的圖像沒有意義。但是,當您希望在不同的螢幕尺寸上顯示不同的圖像時,這可能會成為一個問題,這就是為什麼picture元素是理想的選擇。

為什麼 CSS 不适合

如果您熟悉CSS,您可能會意識到我們可以通過使用一些簡單的CSS屬性來實作非常類似的效果。

img {
  object-fit: cover;
  object-position: center;
}           

這樣做将使圖像填充父元素的整個寬度,然後裁剪圖像,以確定圖像的中心始終可見。這将給我們非常相似的效果,但缺點是即使在小螢幕尺寸下我們隻顯示圖像的一部分,仍然需要下載下傳完整分辨率的圖像。這與我們使用響應式圖像所要實作的目标背道而馳。

結論

響應式圖像可能看起來是一個複雜的話題,但實際上并不需要如此。實作基本的響應式圖像隻需在img标簽中添加srcset屬性,然後讓浏覽器完成其餘工作。如果您想進一步深入,您可以使用sizes屬性來幫助浏覽器選擇正确的圖像,或者如果您想在不同的螢幕尺寸上顯示不同的圖像,可以使用picture元素。

由于文章内容篇幅有限,今天的内容就分享到這裡,文章結尾,我想提醒您,文章的創作不易,如果您喜歡我的分享,請别忘了點贊和轉發,讓更多有需要的人看到。同時,如果您想擷取更多前端技術的知識,歡迎關注我,您的支援将是我分享最大的動力。我會持續輸出更多内容,敬請期待。

原文:https://blog.webdevsimplified.com/2023-05/responsive-images/

非直接翻譯,有自行改編和添加部分,翻譯水準有限,難免有疏漏,歡迎指正

繼續閱讀