詳細的聊一聊如何使用響應(yīng)式圖片,提升網(wǎng)頁加載速度

開篇
確保圖片在所有屏幕尺寸上都能良好顯示是一項困難的任務(wù),因為你需要考慮圖片的大小、圖片的放置位置、顯示圖片的比例、用戶連接的速度等等眾多因素。結(jié)果是,大多數(shù)開發(fā)者只會為所有屏幕尺寸使用同一張圖片,并讓瀏覽器調(diào)整圖片的大小以適應(yīng)屏幕。這是一種不好的做法,因為瀏覽器仍會下載完整尺寸的圖片(通常非常大),即使它只以其一部分尺寸顯示。這會浪費用戶的帶寬,并且會顯著減慢頁面加載速度(尤其是在較慢的連接下)。
解決這個問題的方法是使用響應(yīng)式圖片。響應(yīng)式圖片是根據(jù)用戶的屏幕尺寸進行優(yōu)化的圖片。這意味著圖片將以適合用戶設(shè)備的正確尺寸和質(zhì)量進行下載。這將顯著減少傳輸給用戶的數(shù)據(jù)量,加快頁面加載速度。有許多實現(xiàn)響應(yīng)式圖片的方法,從簡單到復雜。在本文中,我將向您展示如何在您的網(wǎng)站上呈現(xiàn)響應(yīng)式圖片的所有方式。
img srcset 屬性
到目前為止,實現(xiàn)響應(yīng)式圖片最簡單的方法是在img標簽上使用srcset屬性。該屬性允許您定義多個不同尺寸的圖片,然后瀏覽器將自動選擇最適合用戶屏幕尺寸的圖片。
<img
src="tree-1200.jpg"
alt="A tree"
srcset="tree-400.jpg 400w, tree-800.jpg 800w, tree-1200.jpg 1200w"
/>這段代碼可能看起來有些混亂,所以讓我詳細解釋一下其中發(fā)生的事情。首先,我們有了您已經(jīng)熟悉的普通src和alt屬性,它們與所有圖片一樣。在極少數(shù)情況下,如果用戶使用的瀏覽器不支持srcset,那么將使用src URL來顯示圖片。不過,這種情況非常罕見,因為srcset在所有主要瀏覽器中已經(jīng)支持了5-10年。
讓人困惑的是srcset屬性。該屬性接受一個逗號分隔的圖片URL和它們的寬度列表。如果我們看一下列表中的第一項tree-400.jpg 400w,可以看到URL是tree-400.jpg。這個URL的名稱并不重要,但通常當您在不同尺寸上有多個相同的圖片時,您會希望在名稱中加上尺寸信息。
這項內(nèi)容的第二部分是400w。這可能會讓人困惑,因為w不是CSS單位,實際上w代表圖像的實際寬度,以像素為單位。您可以通過在文件瀏覽器/資源管理器中檢查圖像來輕松找到這個寬度。如果您使用的是Windows操作系統(tǒng),可以右鍵單擊圖像,選擇屬性,而在Mac上應(yīng)該有一個名為"獲取信息"的選項。在本例中,圖像的寬度為400像素,因此我們將寬度設(shè)置為400w。
瀏覽器將使用這些信息來自動確定要下載的圖片。例如,如果用戶的屏幕寬度小于400像素,它將使用tree-400.jpg圖像,因為這是可以在不進行任何拉伸/模糊像素的情況下使用的最小圖像。一旦瀏覽器的寬度大于400像素,瀏覽器將切換到使用tree-800.jpg圖像。這是因為400像素的圖像現(xiàn)在比當前屏幕尺寸小,如果使用它會被拉伸/模糊。對于所有屏幕尺寸,這個過程會一直持續(xù),直到瀏覽器達到列表中最大的圖像。
這很棒,因為現(xiàn)在在小屏幕上,瀏覽器將下載一個較小的圖像,而大屏幕仍將獲得高分辨率的圖像。這將顯著減少傳輸給用戶的數(shù)據(jù)量,并加快頁面加載速度。下面是一個示例,展示了這種情況。嘗試將瀏覽器大小調(diào)整為較小的尺寸,然后重新加載頁面,您將看到下載了較小的圖像。
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像素寬的圖像。這是因為瀏覽器還考慮了您設(shè)備的像素密度。如果您使用的是高分辨率設(shè)備或瀏覽器縮放級別較高,瀏覽器將下載一個較大的圖像,以確保在您的屏幕上顯示良好,因為每個CSS像素實際上對應(yīng)屏幕上的多個像素。要檢查設(shè)備的像素密度,您可以在控制臺中使用window.devicePixelRatio。
如何處理不同的像素密度
有時候,您可能有一張圖像在屏幕上始終保持相同的尺寸,但您希望它在高分辨率設(shè)備上看起來很好。例如,如果您的標志始終為100像素寬,在只提供100像素寬圖像的情況下,在高分辨率設(shè)備上會顯得模糊不清。為了解決這個問題,您可以使用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示例非常相似,但主要區(qū)別在于我們使用了類似1.5x和2x的單位,而不是硬編碼的像素值。這些單位指的是屏幕的像素密度。例如,如果某人的屏幕具有每個CSS像素1.25個設(shè)備像素的像素密度,則將使用logo-150.jpg圖像,因為這是可以在不拉伸/模糊像素的情況下使用的最小圖像。
您無需包含1x單位,因為它是默認值。如果您只有兩個圖像,您可以使用logo-100.jpg,logo-200.jpg 2x,而不是logo-100.jpg 1x,logo-200.jpg 2x。
img sizes 屬性
到目前為止,我們介紹的是實現(xiàn)響應(yīng)式圖片的最基本方法,但在許多情況下,您的圖像尺寸實際上并不等于屏幕的寬度。本博客就是一個很好的例子。在小屏幕上,我的博客內(nèi)容(包括圖像)占據(jù)了整個屏幕的寬度,但在較大屏幕上,我將內(nèi)容居中顯示,并設(shè)置了一個有限的最大寬度。如果我們僅使用像上面那樣的srcset,我們的圖像將根據(jù)瀏覽器窗口的完整尺寸進行縮放,這將導致在大屏幕上圖像比實際需要的要大。這就是sizes屬性的用途。
sizes屬性允許您定義圖像的單個尺寸,例如50vw,或者一組媒體查詢,用于確定圖像應(yīng)該使用的尺寸。默認情況下,如果您沒有將sizes屬性添加到img標簽中,它會假定尺寸為100vw,這就是為什么上面的圖像根據(jù)瀏覽器窗口的完整寬度進行縮放。讓我們看一下如何使用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屬性接受一個以逗號分隔的媒體查詢和尺寸列表。為了理解其中的內(nèi)容,讓我們逐個解析列表中的每個項。
我們的第一個項(max-width: 800px)100vw 有兩個部分。第一部分是我們要檢查的媒體查詢。在這種情況下,我們要檢查屏幕寬度是否小于800像素。第二部分是如果媒體查詢?yōu)閠rue時我們要使用的尺寸。在這種情況下,我們使用100vw,這意味著我們希望瀏覽器根據(jù)瀏覽器窗口的完整寬度選擇圖像尺寸。
第二個項800px沒有媒體查詢,而只是一個尺寸。這被視為我們的回退尺寸。如果之前定義的所有媒體查詢都為false,那么它將使用這個回退尺寸。從本質(zhì)上講,您可以將其視為始終為true的媒體查詢。我們通過這個項表達的意思是,假設(shè)我們的圖像在屏幕上占據(jù)了800像素,我們應(yīng)該選擇我們的圖像。然后,瀏覽器將使用這個尺寸來確定要下載的圖像。如果您的瀏覽器具有高分辨率或您在頁面上進行了縮放,它可能會下載比800像素更大的圖像,但通常情況下,這是確保圖像不會過大的一種好方法。
將這兩個項組合起來,基本上是在說我們的圖像應(yīng)該根據(jù)瀏覽器的寬度選擇,在800像素之前。在那一點上,圖像在我們的屏幕上永遠不會占用超過800像素的空間,所以我們應(yīng)該根據(jù)這個800像素的尺寸來調(diào)整我們的圖像尺寸。這是我為這個博客添加響應(yīng)式圖像的代碼方式,因為我的博客在較大的屏幕尺寸上受到最大寬度的限制。讓我們看一個實際的示例。
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"
/>
我添加了許多不同的圖像尺寸,這樣您就可以看到它們?nèi)绾闻c不同的像素密度配合工作。如果您使用的是高分辨率設(shè)備,您可能會注意到瀏覽器下載了比800像素更大的圖像。您還可以通過縮放設(shè)備來模擬此過程,因為您的設(shè)備縮放得越多,像素密度就越高,如果您縮放足夠多,瀏覽器將需要下載更高分辨率的圖像,以確保在屏幕上顯示良好。
潛在的陷阱
sizes屬性非常強大,但在使用它時需要注意以下幾點。
順序很重要
如果您的sizes屬性中有多個媒體查詢,將選擇第一個為true的媒體查詢對應(yīng)的圖像。這意味著您的媒體查詢的順序很重要。
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像素時才為真,而在這些尺寸范圍內(nèi)第一個媒體查詢將始終為真,因此它將始終被優(yōu)先選擇。為了解決這個問題,您需要重新排序媒體查詢,使最具體的媒體查詢排在最前面,最不具體的媒體查詢排在最后。
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"
/>同樣重要的是,確保您的默認尺寸(即沒有媒體查詢的尺寸)始終放在最后,因為它總是為真,所以如果它排在最前面,它將始終被選擇,而不考慮其他媒體查詢。
使用百分比
到目前為止,我已經(jīng)向您展示了如何使用像px這樣的具體尺寸,以及如何使用基于瀏覽器窗口的尺寸,比如vw,但是百分比尺寸(如50%)該怎么辦呢?不幸的是,在sizes屬性中不支持百分比尺寸。原因是瀏覽器在不知道父元素的寬度之前,無法確定百分比定義的內(nèi)容的寬度。這意味著瀏覽器必須等到整個頁面加載完成后才能確定要下載哪個圖像。這將是一個糟糕的用戶體驗,因為用戶必須等到整個頁面加載完成才能看到任何圖像。
picture 元素
到目前為止,我們主要討論了如何以不同尺寸渲染相同的圖像,以幫助提高加載時間,但這并沒有涵蓋在不同屏幕尺寸下顯示不同圖像的情況。例如,如果您的頁面有一個寬度跨越整個頁面的大標題,您可能希望在移動設(shè)備和桌面設(shè)備上顯示不同的圖像,因為您可以在桌面設(shè)備上使用更多細節(jié)的圖像。這就是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>
如果你調(diào)整瀏覽器的大小,你應(yīng)該會看到圖像在兩個不同版本之間變化。如果你使用的是移動設(shè)備,你可能需要縮放來觀察圖像的變化。我們?yōu)檩^小的屏幕尺寸提供了更裁剪的圖像版本,因為在較小的屏幕上,圖像的焦點——人物——會變得太小。
現(xiàn)在讓我們看一下實際的代碼,了解它是如何工作的。為了讓picture元素起作用,你至少需要將一個普通的img標簽放在picture元素的最后。
<picture>
<img src="hiking-wide.jpg" alt="Someone jumping on a hike" />
picture>這樣做將只是像普通的img標簽一樣渲染圖像。在這里,更加高級的是使用source元素。除了默認版本之外,每個圖像的變體都應(yīng)該有自己的source元素。在我們的例子中,我們只有一個source元素,但您可以根據(jù)需要添加任意數(shù)量的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元素內(nèi)部,您有兩個主要屬性。srcset屬性的工作方式與img標簽的srcset屬性相同。這意味著,如果我們有hiking-narrow.jpg圖像的多個分辨率,我們可以將它們包含在srcset屬性中。不過,在使用picture元素時,每個source元素通常只有一個分辨率,因此您可以將其作為srcset屬性中的唯一URL。
另一個屬性是media屬性。它的工作方式類似于sizes屬性中的媒體查詢,但是在source元素的media屬性中,您只能定義一個媒體查詢。這些查詢與sizes屬性一樣,從上到下逐個檢查,只有第一個匹配的媒體查詢會被使用。如果沒有任何媒體查詢匹配,則使用img標簽作為備選項,這也是為什么我們沒有針對較大屏幕尺寸專門設(shè)置source元素的原因。
為什么要使用picture元素而不是其他替代方案
對于picture元素的一個大誤解是,為什么要使用它而不是img元素的sizes屬性或CSS。
為什么 sizes 不適合
sizes屬性不適合此任務(wù)的主要原因是,picture元素始終會切換到與當前屏幕尺寸匹配的source元素中定義的圖像。這意味著,如果您通過縮放或調(diào)整窗口大小來更改屏幕尺寸,它將切換到正確的圖像。
sizes屬性的工作方式類似,但只適用于增大屏幕尺寸的情況。如果您的屏幕尺寸縮小,瀏覽器將不會切換或下載較小的圖像,因為它已經(jīng)有了較大的圖像,因此將繼續(xù)渲染該圖像。這非常好,因為它可以節(jié)省帶寬,因為當您已經(jīng)擁有較大的圖像時,下載較小的圖像沒有意義。但是,當您希望在不同的屏幕尺寸上顯示不同的圖像時,這可能會成為一個問題,這就是為什么picture元素是理想的選擇。
為什么 CSS 不適合
如果您熟悉CSS,您可能會意識到我們可以通過使用一些簡單的CSS屬性來實現(xiàn)非常類似的效果。
img {
object-fit: cover;
object-position: center;
}這樣做將使圖像填充父元素的整個寬度,然后裁剪圖像,以確保圖像的中心始終可見。這將給我們非常相似的效果,但缺點是即使在小屏幕尺寸下我們只顯示圖像的一部分,仍然需要下載完整分辨率的圖像。這與我們使用響應(yīng)式圖像所要實現(xiàn)的目標背道而馳。
結(jié)論
響應(yīng)式圖像可能看起來是一個復雜的話題,但實際上并不需要如此。實現(xiàn)基本的響應(yīng)式圖像只需在img標簽中添加srcset屬性,然后讓瀏覽器完成其余工作。如果您想進一步深入,您可以使用sizes屬性來幫助瀏覽器選擇正確的圖像,或者如果您想在不同的屏幕尺寸上顯示不同的圖像,可以使用picture元素。
由于文章內(nèi)容篇幅有限,今天的內(nèi)容就分享到這里,文章結(jié)尾,我想提醒您,文章的創(chuàng)作不易,如果您喜歡我的分享,請別忘了點贊和轉(zhuǎn)發(fā),讓更多有需要的人看到。同時,如果您想獲取更多前端技術(shù)的知識,歡迎關(guān)注我,您的支持將是我分享最大的動力。我會持續(xù)輸出更多內(nèi)容,敬請期待。
原文:
https://blog.webdevsimplified.com/2023-05/responsive-images/非直接翻譯,有自行改編和添加部分,翻譯水平有限,難免有疏漏,歡迎指正
