<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          《現(xiàn)代圖片性能優(yōu)化及體驗(yàn)優(yōu)化指南》全集【建議收藏】

          共 26150字,需瀏覽 53分鐘

           ·

          2023-04-23 18:15

          在之前,《現(xiàn)代圖片性能優(yōu)化及體驗(yàn)優(yōu)化指南》分了 5 篇發(fā)出,本文是全部 5 篇的合集,方便大家收藏閱讀。

          圖片資源,在我們的業(yè)務(wù)中可謂是占據(jù)了非常大頭的一環(huán),尤其是其對(duì)帶寬的消耗是十分巨大的。

          對(duì)圖片的性能優(yōu)化及體驗(yàn)優(yōu)化在今天就顯得尤為重要。本文,就將從各個(gè)方面闡述,在各種新特性滿(mǎn)頭飛的今天,我們可以如何盡可能的對(duì)我們的圖片資源,進(jìn)行性能優(yōu)化及體驗(yàn)優(yōu)化。

          圖片類(lèi)型的選取及 Picture 標(biāo)簽的使用

          首先,從圖片的類(lèi)型上而言,除了常見(jiàn)的 PNG-8/PNG-24,JPEG,GIF 之外,我們更多的關(guān)注另外幾個(gè)較新的圖片格式:

          • WebP
          • JPEG XL
          • AVIF

          首先,通過(guò)一張表格,快速過(guò)一下這幾個(gè)圖片,我們將從圖片類(lèi)型、透明通道、動(dòng)畫(huà)、編解碼性能、壓縮算法、顏色支持、內(nèi)存占用、兼容性方面,對(duì)比它們:

          圖片類(lèi)型 Alpha 通道 動(dòng)畫(huà) 編解碼性能 壓縮算法 顏色支持 內(nèi)存占用 兼容性
          GIF 支持 支持 較高 無(wú)損壓縮 索引色(256) 基本一致 ALL
          PNG-8/PNG-24 支持 不支持 較高 無(wú)損壓縮 索引色(256)\直接色 基本一致 ALL
          JPEG 不支持 不支持 較高 有損壓縮 直接色 基本一致 ALL
          WebP 支持 支持 編解碼性能差(低配設(shè)備更為顯著) 有損壓縮\無(wú)損壓縮 直接色 基本一致 高版本 Chrome\Opera\Android
          JPEG XL 支持 支持 編解碼性能優(yōu)于 WebP 有損壓縮\無(wú)損壓縮 直接色 基本一致 部分高版本 Chrome\Opera\Firefox\Edge
          AVIF 支持 支持 編解碼性能優(yōu)于 WebP,低于 JPEG XL 有損壓縮\無(wú)損壓縮 直接色 基本一致 高版本 Chrome\Opera\Android\Edge

          首先,了解了解上述的一些參數(shù)含義:

          • Alpha 通道:圖片是否支持透明的特性

          當(dāng)然,需要指出的是,Alpha 沒(méi)有透明度的意思,不代表透明度。opacity 和 transparency 才和透明度有關(guān),前者是不透明度,后者是透明度。比如 css 中的「opacity: 0.5」就是設(shè)定元素有 50% 的不透明度。后來(lái) Alvy Ray Smith 提出每個(gè)像素再增加一個(gè) Alpha 通道,取值為0到1,用來(lái)儲(chǔ)存這個(gè)像素是否對(duì)圖片有「貢獻(xiàn)」,0代表透明、1代表不透明。也就是說(shuō),「Alpha 通道」儲(chǔ)存一個(gè)值,其外在表現(xiàn)是「透明度」,Alpha 和透明度沒(méi)啥關(guān)系

          • 動(dòng)畫(huà):很好理解,圖片是否支持多幀率動(dòng)態(tài)圖片,類(lèi)似于 GIF
          • 編解碼性能:圖像的解碼與編碼。這個(gè)很關(guān)鍵,很多人對(duì)待圖片容易忽視圖片的編解碼性能,解碼圖像主要從圖像文件中讀出圖像數(shù)據(jù),而編碼則是將圖像數(shù)據(jù)寫(xiě)入圖像文件。解碼與編碼的過(guò)程正好相反。而這兩者的性能耗時(shí)會(huì)影響我們頁(yè)面的的展示性能。
          • 壓縮算法:該圖片格式是否支持壓縮,支持的話,圖片的壓縮又會(huì)分為無(wú)損壓縮與有損壓縮

          有損壓縮算法是一種數(shù)據(jù)壓縮方法,經(jīng)過(guò)此方法壓縮、解壓的數(shù)據(jù)會(huì)與原始數(shù)據(jù)不同但是非常接近。原理是借由將次要的信息數(shù)據(jù)舍棄,犧牲一些質(zhì)量來(lái)減少數(shù)據(jù)量、提高壓縮比無(wú)損壓縮指數(shù)據(jù)經(jīng)過(guò)壓縮后,信息不受損失,還能完全恢復(fù)到壓縮前的原樣。無(wú)損壓縮通常用于嚴(yán)格要求“經(jīng)過(guò)壓縮、解壓縮的數(shù)據(jù)必須與原始數(shù)據(jù)一致”的場(chǎng)合。

          • 顏色支持:會(huì)分為索引色與直接色,在過(guò)去,為了節(jié)省存儲(chǔ)空間,并非所有圖片都能支持所有顏色值,因此存在索引色這種優(yōu)化方式。

          索引顏色是一種以有限的方式管理數(shù)字圖像顏色的技術(shù),以節(jié)省計(jì)算機(jī)內(nèi)存和文件存儲(chǔ),同時(shí)加速顯示刷新和文件傳輸。即用一個(gè)數(shù)字來(lái)代表(索引)一種顏色,在存儲(chǔ)圖片的時(shí)候,存儲(chǔ)一個(gè)數(shù)字的組合,同時(shí)存儲(chǔ)數(shù)字到圖片顏色的映射。這種方式只能存儲(chǔ)有限種顏色。索引色常見(jiàn)有1位(即黑白),8位(即灰階/256色),16位(即高彩),24位(即真彩),30/36/48位(即全彩)。直接色使用四個(gè)數(shù)字來(lái)代表一種顏色,這四個(gè)數(shù)字分別代表這個(gè)顏色中紅色、綠色、藍(lán)色以及透明度(即 RGBA)。現(xiàn)在流行的顯示設(shè)備可以在這四個(gè)維度分別支持256種變化,所以直接色可以表示2的32次方種顏色。

          • 內(nèi)存占用:圖片對(duì)內(nèi)存資源的占用
          • 兼容性:影響圖片格式能否大規(guī)模推廣的核心要素之一

          WebP vs JPEG XL vs AVIF: JPEG 替代之戰(zhàn)

          因?yàn)閭鹘y(tǒng)的 PNG-8/PNG-24,JPEG,GIF 各自或多或少都存在一些問(wèn)題,近些年來(lái)它們的替代方案之爭(zhēng)也愈演愈烈,核心領(lǐng)跑者可能是?WebPJPEG XLAVIF

          再簡(jiǎn)單了解了解它們:

          WebP

          WebP 最初由 Google 在 2010 年 9 月發(fā)布,其特性總結(jié)如下:

          1. 可以同時(shí)提供無(wú)損/有損壓縮(像 JPEG 一樣)和支持透明度(像 PNG 一樣)的圖片文件格式
          2. 支持動(dòng)畫(huà)效果(像 GIF 一樣)
          3. WebP 主要優(yōu)勢(shì)在于有損編碼,其無(wú)損編碼的性能和壓縮比表現(xiàn)一般
          4. WebP 的缺點(diǎn)在于其編解碼性能不是特別理想
          5. 在兼容性方面,除了 IE,基本已經(jīng)得到了全系列瀏覽器支持

          對(duì)于復(fù)雜的圖像(比如照片)來(lái)說(shuō),WebP 無(wú)損編碼表現(xiàn)并不好,但有損編碼表現(xiàn)卻非常棒。相近質(zhì)量的圖片解碼速度 WebP 相距 JPEG 也已經(jīng)相差不大了,而文件壓縮比卻能提升不少。

          下圖是我之前還在 TX 的時(shí)候做的一個(gè)測(cè)試對(duì)比:

          c04f22c3f9aa87ab97aaa73ac7f220f0.webp

          加載同樣張數(shù)的 JPEG 與 WebP 的耗時(shí)對(duì)比:

          42a5118e62b0ced373951e6bca1d2764.webp

          對(duì)于 WebP 圖片格式,簡(jiǎn)單做個(gè)總結(jié):

          1. 目前 WebP 與 JPEG 相比較,據(jù)資料考證,編碼速度慢 10 倍,解碼速度慢 1.5 倍
          2. WebP 雖然會(huì)增加額外的解碼時(shí)間,但由于大幅減少了文件體積,縮短了加載的時(shí)間,大頁(yè)面圖片量較多的場(chǎng)景下,頁(yè)面的渲染速度是有較大加快的
          3. 目前而言,是 WebP、JPEG XL、AVIF 三者中兼容性最好的

          截止至(2023-02-05)的兼容性圖:

          623446fa14a4d8d1ced8f17642af35e4.webp

          JPEG XL

          JPEG XL 由聯(lián)合圖像專(zhuān)家組(開(kāi)發(fā)原始 JPEG 標(biāo)準(zhǔn)的同一組織)于 2021 年發(fā)布,旨在成為傳統(tǒng) JPEG 的長(zhǎng)期替代品。作為一種免版稅的開(kāi)源標(biāo)準(zhǔn),JPEG XL 的創(chuàng)建者希望其格式的開(kāi)放性能夠吸引網(wǎng)絡(luò)開(kāi)發(fā)人員采用該標(biāo)準(zhǔn),該格式的擴(kuò)展名為?.jxl,JXL 核心比特流于 2021 年 1 月凍結(jié),文件格式于 2021 年 4 月定稿。:

          JPEG XL 中的 X 指 2000 年以來(lái)的多個(gè) JPEG 標(biāo)準(zhǔn)的名稱(chēng):JPEG XT[1]、JPEG XR[2]、JPEG XS[3],而 L 表示 'long-term',表示“長(zhǎng)期”。創(chuàng)建這種格式是為替換舊的JPEG文件格式[4],并使用足夠長(zhǎng)的時(shí)間。

          其主要特點(diǎn)有:

          • 與傳統(tǒng)圖像格式(例如JPEG、GIF和PNG)相比,有著更佳的效率與更豐富的功能
          • 全面支持廣色域和 HDR,支持 Alpha 通道,支持多幀(也就是動(dòng)畫(huà)支持)
          • 有損壓縮時(shí):相同的視覺(jué)質(zhì)量,比 JPEG 小約 60%。
          • 無(wú)損壓縮時(shí):比 PNG 減小約 35%(對(duì)于 HDR,減小 50%)。
          • 支持無(wú)損 JPEG 轉(zhuǎn)碼,減小約 20% 文件大小。
          • 漸進(jìn)式解碼,專(zhuān)為支持不同顯示分辨率的響應(yīng)式加載
          • 開(kāi)源免費(fèi):具有使用三條款版BSD許可證[5]的開(kāi)源[6]參考實(shí)現(xiàn)的免版稅格式

          看看同一張圖片,相同質(zhì)量下的大小表現(xiàn):

          6f027285791d858c48e279a3080ff892.webp

          數(shù)據(jù)來(lái)源:技術(shù)周刊 2021-04-15:2021最值得期待的新技術(shù) JPEG XL[7]

          JPEG XL 是目前而言,最有可能全面替代傳統(tǒng)圖片格式(Gif、PNG、JPEG)的下一代標(biāo)準(zhǔn),當(dāng)然,在今天,需要看看其兼容性:

          b4ee738792d4e713ee014414d507ae4b.webp

          好吧,目前的兼容有點(diǎn)離譜。Chrome 從 91 版本開(kāi)始已經(jīng)實(shí)驗(yàn)室性質(zhì)支持了?.jxl?格式的圖片,需要通過(guò)?--enable-features=JXL?配置開(kāi)啟。憾的是,從 Chrome 110 開(kāi)始,Chrome 又不再支持 JPEG?XL??

          有趣的是,Chrome 從 110 版本開(kāi)始中棄用了對(duì) JPEG-XL 的支持,谷歌的回答是,人們對(duì) JPEG-XL 沒(méi)有足夠的興趣,并且與現(xiàn)有格式相比也沒(méi)有足夠的優(yōu)勢(shì)。谷歌之前一直對(duì) JPEG 的支持都是實(shí)驗(yàn)性的性質(zhì)的,他們認(rèn)為 JPEG XL 缺乏生態(tài)系統(tǒng)支持,并且該格式?jīng)]有足夠多的好處(相對(duì) WebP 和 AVIF)。也就是說(shuō),目前而言,Chrome 對(duì) WebP 和 AVIF 等替代格式更感興趣。

          AVIF

          最后,我們?cè)賮?lái)看看 AVIF 格式圖片。

          AVIF 是由開(kāi)放媒體聯(lián)盟 (AOM) 開(kāi)發(fā)并于 2019 年發(fā)布的另一種最新圖像格式。該格式基于 AV1 視頻編解碼器,源自視頻幀。其特點(diǎn)如下:

          • 同樣的,與傳統(tǒng)圖像格式(例如JPEG、GIF和PNG)相比,有著更佳的效率與更豐富的功能
          • 支持 Alpha 通道,支持動(dòng)態(tài)圖像[8]和動(dòng)畫(huà)[9]
          • 支持有損、無(wú)損壓縮。AVIF 文件在低保真有損圖像壓縮方面表現(xiàn)出色(比 JPEG XL 更優(yōu))。壓縮的 AVIF 圖像保留了很高的圖片質(zhì)量,避免了惱人的壓縮偽影等問(wèn)題
          • 相對(duì)而言,AVIF 的解碼和編碼速度不如 JPEG XL,它不支持漸進(jìn)式渲染
          • 最后,再看看兼容性,目前(2023-02-05)它的兼容性介于 WebP 與 JPEG XL 之間

          看看 CaniUse 的數(shù)據(jù):

          f7abfa3bd9c6077ecdbcdfd5859cb30a.webp

          下圖是 WebP vs JPEG XL vs AVIF 三者在圖片解碼上的性能表現(xiàn):

          933308d94e3237faa24c7dbe4d5d6376.webp

          圖片來(lái)源于:Encode.su -- JPEG XL vs. AVIF[10]

          從圖中可以看到,對(duì)于解碼性能的對(duì)比,結(jié)果居然是 WebP > AVIF > JPEG XL 。JPEG XL 的編解碼性能并沒(méi)有其描述的那么強(qiáng)大。

          圖片格式總結(jié)

          總結(jié)一下,WebP、AVIF 和 JPEG XL 都是瀏覽器不廣泛支持的新型圖像格式。雖然 WebP、AVIF 已經(jīng)存在很長(zhǎng)時(shí)間,但到今天,影響它們大規(guī)模使用的依舊是兼容問(wèn)題。

          JPEG XL、AVIF、Web 各自有各自的特點(diǎn)與優(yōu)勢(shì),并且都未完全得到任何瀏覽器的支持。

          雖然 AVIF、JPEG XL 等新型圖片格式未得到任何瀏覽器的完全支持,但是在新版本的 Chrome、Firefox 和 Edge Chromium,可以使用配置標(biāo)志啟用對(duì)應(yīng)圖像格式,配合 HTML 的 Picture 標(biāo)簽,我們還是可以一定程度上對(duì)我們的圖片進(jìn)行格式選擇上的優(yōu)化的。

          這,就可以引出我們要說(shuō)的第二部分 -- HTML Picture 標(biāo)簽的使用。

          Picture 元素的使用

          HTML5 規(guī)范新增了 Picture Element。那么?<picture>?元素的作用是什么呢?

          <picture>?元素通過(guò)包含零或多個(gè)?<source>?元素和一個(gè)?<img>?元素來(lái)為不同的顯示/設(shè)備場(chǎng)景提供圖像版本。瀏覽器會(huì)選擇最匹配的子?<source>?元素,如果沒(méi)有匹配的,就選擇?<img>?元素的 src 屬性中的 URL。然后,所選圖像呈現(xiàn)在?<img>?元素占據(jù)的空間中。

          什么意思呢?怎么使用?<picture>?元素呢?

          假設(shè),沒(méi)有?<picture>?,只有?<img>?元素,我們想盡可能在支持一些現(xiàn)代圖片格式的瀏覽器上使用類(lèi)似于上述我們提到的 WebP、AVIF 和 JPEG XL ?等圖片格式,而不支持的瀏覽器回退使用常規(guī)的 JPEG、PNG 等。沒(méi)錯(cuò),就是一種漸進(jìn)增強(qiáng)的思想,該怎么辦呢?

          只能是 JavaScript 去寫(xiě)對(duì)應(yīng)的邏輯,通過(guò) JS 腳本進(jìn)行特性查詢(xún),動(dòng)態(tài)賦值給?<img>?的 src。

          我們來(lái)看看對(duì)應(yīng)的語(yǔ)法:

              <picture>
          ??<!--?可能是一些對(duì)兼容性有要求的,但是性能表現(xiàn)更好的現(xiàn)代圖片格式-->
          ??<source?src="image.avif"?type="image/avif">
          ??<source?src="image.jxl"?type="image/jxl">
          ??<source?src="image.webp"?type="image/webp">

          ???<!--?最終的兜底方案-->
          ??<img?src="image.jpg"?type="image/jpeg">
          </picture>?

          而有了?<picture>?后,瀏覽器將原生支持上述的一些列操作,簡(jiǎn)而言之,<picture>?元素的作用:

          1. 通過(guò)?<source>?給出一系列對(duì)兼容性有所要求的現(xiàn)代圖片格式選項(xiàng)
          2. 通過(guò)?<img>?給出兜底的高兼容性圖片格式選項(xiàng)
          3. 瀏覽器通過(guò)對(duì)給出的圖片格式做特性檢測(cè),要決定加載哪個(gè) URL,user agent 檢查每個(gè)?<source>?的 srcset、media 和 type 屬性,來(lái)選擇最匹配頁(yè)面當(dāng)前布局、顯示設(shè)備特征等的兼容圖像。
          4. 最終,所選圖像呈現(xiàn)在?<img>?元素占據(jù)的空間中

          本章總結(jié)

          總結(jié)一下,本文對(duì)常見(jiàn)的圖片格式以及最新的幾種未被大規(guī)模兼容的圖片格式進(jìn)行的對(duì)比,它們分別是:

          • PNG-8/PNG-24
          • JPEG
          • GIF
          • WebP
          • JPEG XL
          • AVIF

          其后,著重介紹了 3 種現(xiàn)代圖片格式:WebP、JPEG XL、AVIF。相對(duì)于 JPEG 等傳統(tǒng)格式,它們?cè)谏时憩F(xiàn)、動(dòng)畫(huà)支持、是否支持無(wú)損有損壓縮、壓損比率、編解碼性能上有著更進(jìn)一步的提升,正在成為下一階段 Web 圖像的標(biāo)準(zhǔn)。

          最后,介紹了?<picture>?元素,借助它,我們能更好的實(shí)現(xiàn)圖片的漸進(jìn)增強(qiáng)。

          適配不同的屏幕尺寸及 DPR

          第二個(gè)模塊,我們來(lái)看看圖片資源如何更好的適配不同的屏幕尺寸。

          這里首先會(huì)涉及一個(gè)預(yù)備知識(shí),屏幕的 DPR 值,那么,什么是 DPR 呢?要了解 DPR,又需要知道什么是設(shè)備獨(dú)立像素?以及?物理像素

          設(shè)備獨(dú)立像素

          以 iPhone6/7/8為例,這里我們打開(kāi) Chrome 開(kāi)發(fā)者工具:

          b11c59c4aa8676d7092e119c15a89ae9.webp

          這里的?375 * 667?表示的是什么呢,表示的是設(shè)備獨(dú)立像素(DIP),也可以理解為 CSS 像素,也稱(chēng)為邏輯像素:

          設(shè)備獨(dú)立像素 = CSS 像素 = 邏輯像素

          如何記憶呢?這里使用 CSS 像素來(lái)記憶,也就是說(shuō)。我們?cè)O(shè)定一個(gè)寬度為 375px 的 div,剛好可以充滿(mǎn)這個(gè)設(shè)備的一行,配合高度 667px ,則 div 的大小剛好可以充滿(mǎn)整個(gè)屏幕。

          物理像素

          OK,那么,什么又是物理像素呢。我們到電商網(wǎng)站購(gòu)買(mǎi)手機(jī),都會(huì)看一看手機(jī)的參數(shù),以 JD 上的 iPhone7 為例:

          dad6d42279e4db541e15a9bc673d655e.webp

          可以看到,iPhone7 的分辨率是?1334 x 750,這里描述的就是屏幕實(shí)際的物理像素。

          物理像素,又稱(chēng)為設(shè)備像素。顯示屏是由一個(gè)個(gè)物理像素點(diǎn)組成的,1334 x 750?表示手機(jī)分別在垂直和水平上所具有的像素點(diǎn)數(shù)。通過(guò)控制每個(gè)像素點(diǎn)的顏色,就可以使屏幕顯示出不同的圖像,屏幕從工廠出來(lái)那天起,它上面的物理像素點(diǎn)就固定不變了,單位為pt。

          設(shè)備像素 = 物理像素

          DPR(Device Pixel Ratio) 設(shè)備像素比

          OK,有了上面兩個(gè)概念,就可以順理成章引出下一個(gè)概念。DPR(Device Pixel Ratio) 設(shè)備像素比,這個(gè)與我們通常說(shuō)的視網(wǎng)膜屏(多倍屏,Retina屏)有關(guān)。

          設(shè)備像素比描述的是未縮放狀態(tài)下,物理像素和設(shè)備獨(dú)立像素的初始比例關(guān)系。

          簡(jiǎn)單的計(jì)算公式:

          DPR = 物理像素 / 設(shè)備獨(dú)立像素

          我們套用一下上面 iPhone7 的數(shù)據(jù)(取設(shè)備的物理像素寬度與設(shè)備獨(dú)立像素寬度進(jìn)行計(jì)算):

          iPhone7’s DPR = iPhone7’s 物理像素寬度 / iPhone7's 設(shè)備獨(dú)立像素寬度 = 2

          750 / 375 = 2 或者是 1334 / 667 = 2

          可以得到 iPhone7 的 dpr 為 2。也就是我們常說(shuō)的視網(wǎng)膜屏幕。

          視網(wǎng)膜(Retina)屏幕是蘋(píng)果公司"發(fā)明"的一個(gè)營(yíng)銷(xiāo)術(shù)語(yǔ)。蘋(píng)果公司將?dpr > 1?的屏幕稱(chēng)為視網(wǎng)膜屏幕。

          a19ef19bf796bbb018029f1ea80795d3.webp

          在視網(wǎng)膜屏幕中,以 dpr = 2 為例,把 4(2x2) 個(gè)像素當(dāng) 1 個(gè)像素使用,這樣讓屏幕看起來(lái)更精致,但是元素的大小本身卻不會(huì)改變:

          ece1e722db77bdc2aa872e726f94d217.webp

          OK,我們?cè)賮?lái)看看 iPhone XS Max:

          4aad80e5cf7e6600bf4a1f59a01bfbc6.webp

          它的物理像素如上圖是?2688 x 1242

          5a3088acb316b861fb7e189f1bca5eba.webp

          它的 CSS 像素是?896 x 414,很容易得出 iPhone XS Max 的 dpr 為 3。

          為不同 DPR 屏幕,提供恰當(dāng)?shù)膱D片

          那么,DPR 和圖片適配有什么關(guān)系呢?

          舉個(gè)例子,同樣的 CSS 像素大小下,屏幕如果有不同 DPR,同樣大小的圖片渲染出來(lái)的效果不盡相同。

          我們以?dpr = 3?的手機(jī)為例子,在?300 x 389?CSS 像素大小的范圍內(nèi),渲染?1倍/2倍/3倍?圖的效果如下:

          e4739405115909955d07cf47a045c015.webp

          實(shí)際圖片所占的物理像素為 900 x 1167。

          可以看到,在高 DPR 設(shè)備下提供只有 CSS 像素大小的圖片,是非常模糊的。

          因此,為了在不同的 DPR 屏幕下,讓圖片看起來(lái)都不失真,我們需要為不同 DPR 的圖片,提供不同大小的圖片。

          那么,有哪些可行的解決方案呢?

          方案一:無(wú)腦多倍圖

          假設(shè),在移動(dòng)端假設(shè)我們需要一張 CSS 像素為?300 x 200?的圖像,考慮到現(xiàn)在已經(jīng)有了 dpr = 3 的設(shè)備,那么要保證圖片在 dpr = 3 的設(shè)備下也正常高清展示,我們最大可能需要一張?900 x 600?的原圖。

          這樣,不管設(shè)備的 dpr 是否為 3,我們統(tǒng)一都使用 3 倍圖。這樣即使在 dpr = 1,dpr = 2 的設(shè)備上,也能非常好的展示圖片。

          當(dāng)然這樣并不可取,會(huì)造成大量帶寬的浪費(fèi)。

          現(xiàn)代瀏覽器,提供了更好的方式,讓我們能夠根據(jù)設(shè)備 dpr 的不同,提供不同尺寸的圖片。

          方案二:媒體查詢(xún)

          方案二,我們可以考慮使用媒體查詢(xún)。到今天,我們可以通過(guò)相應(yīng)的媒體查詢(xún),得知當(dāng)前的設(shè)備的 DPR 值,這樣,我們就可以在對(duì)應(yīng)的媒體查詢(xún)中,使用對(duì)應(yīng)的圖片。

          像是這樣:

              #id?{?
          ????background:?url(xxx@2x.png)?
          }
          @media?(device-pixel-ratio:?2)?{
          ????#id?{?
          ????????background:?url(xxx@2x.png)?
          ????}
          }
          @media?(device-pixel-ratio:?3)?{
          ????#id?{?
          ????????background:?url(xxx@3x.png)?
          ????}
          }

          這個(gè)方案的缺點(diǎn)在于:

          1. 要寫(xiě)的代碼可能太多了,而且,可能存在一些介于 1~2,2~3 之間的 DPR 值,不好窮舉出所有場(chǎng)景
          2. 需要注意語(yǔ)法需要的兼容性,需要添加前綴,譬如?-webkit-min-device-pixel-ratio,當(dāng)然這個(gè)可以由?autoprefixer?輔助解決

          方案三:CSS 配合 image-set 語(yǔ)法

          image-set?屬于 CSS background 中的一種語(yǔ)法,image-set()?函數(shù)為設(shè)備提供最合適的圖像分辨率,它提供一組圖像選項(xiàng),每個(gè)選項(xiàng)都有一個(gè)相關(guān)的 DPR 聲明,瀏覽器將從中選擇最適合設(shè)備的圖像進(jìn)行設(shè)置。

          什么意思呢,來(lái)看看代碼:

              .img?{
          ????/*?不支持?image-set?的瀏覽器*/
          ????background-image:?url('../[email protected]');

          ????/*?支持?image-set?的瀏覽器*/
          ????background-image:?image-set(
          ????????url('./[email protected]')?2x,
          ????????url('./[email protected]')?3x
          ????);
          }

          這樣一看,作用應(yīng)該很清晰了。對(duì)于支持?image-set?語(yǔ)法的瀏覽器:

          1. 如果其設(shè)備對(duì)應(yīng)的 DPR 為 2,會(huì)選取這條?url('./[email protected]') 2x?記錄,也就是最終生效的 URL 是?'./[email protected]'
          2. 如果其設(shè)備對(duì)應(yīng)的 DPR 為 3,會(huì)選取這條?url('./[email protected]') 3x?記錄,也就是最終生效的 URL 是?'./[email protected]'

          其中的?2x3x?就是用于匹配 DRP的。

          使用?image-set?的一些痛點(diǎn)與媒體查詢(xún)方案類(lèi)似。代碼量與兼容性語(yǔ)法,而且難以匹配所有情況。

          方案四:srcset 配合 1x 2x 像素密度描述符

          簡(jiǎn)單來(lái)說(shuō),srcset 可以根據(jù)不同的 dpr 拉取對(duì)應(yīng)尺寸的圖片:

              <div?class='illustration'>
          ???<img?src='illustration-small.png'
          ???????srcset='images/illustration-small.png?1x,
          ???????????????images/illustration-big.png?2x'

          ???>

          </div>

          上面?srcset?里的 1x,2x 表示?像素密度描述符,表示

          • 當(dāng)屏幕的 dpr = 1 時(shí),使用?images/illustration-small.png?這張圖
          • 當(dāng)屏幕的 dpr = 2 時(shí),使用?images/illustration-big.png?這張圖
          • 如果不支持?srcset?語(yǔ)法,src='illustration-small.png'?將會(huì)是最終的兜底方案

          方案五:srcset 屬性配合 sizes 屬性 w 寬度描述符

          上面 1x,2x 的寫(xiě)法比較容易接受易于理解。

          但是,上述 3 種方案都存在統(tǒng)一的問(wèn)題,只考慮了 DPR,但是忽略了響應(yīng)性布局的復(fù)雜性與屏幕的多樣性

          因此,規(guī)范還推出了一種方案 --?srcset 屬性配合 sizes 屬性 w 寬度描述符

          srcset?屬性還有一個(gè) w 寬度描述符,配合?sizes?屬性一起使用,可以覆蓋更多的面。

          sizes?屬性怎么理解呢?它定義圖像元素在不同的視口寬度時(shí),可能的大小值。

          以下面這段代碼為例子:

              
                <img?
          ????????sizes?=?“(min-width:?600px)?600px,?300px"?
          ????????src?=?"photo.png"?
          ????????srcset?=?[email protected]?300w,
          ???????????????????????photo@2x.png?600w,
          ???????????????????????photo@3x.png?1200w,
          >

          解析一下:

          sizes = “(min-width: 600px) 600px, 300px"?的意思是:

          1. 如果屏幕當(dāng)前的 CSS 像素寬度大于或者等于 600px,則圖片的 CSS 寬度為 600px
          2. 反之,則圖片的 CSS 寬度為 300px

          也就是 sizes 屬性聲明了在不同寬度下圖片的 CSS 寬度表現(xiàn)。這里可以理解為,大屏幕下圖片寬度為 600px,小屏幕下圖片寬度為 300px。

          需要注意的是,這里大屏、小屏下圖片具體的寬度表現(xiàn),還是需要借助媒體查詢(xún)代碼,經(jīng)由 CSS 實(shí)現(xiàn)的

          srcset = “[email protected] 300w, [email protected] 600w, [email protected] 1200w?里面的 300w,600w,900w 叫寬度描述符。

          那么,怎么確定當(dāng)前場(chǎng)景會(huì)選取哪張圖片呢?

          當(dāng)前屏幕 dpr = 2 ,CSS 寬度為 375px

          當(dāng)前屏幕 CSS 寬度為 375px,則圖片 CSS 寬度為 300px。分別用上述 3 個(gè)寬度描述符的數(shù)值除以 300。

          1. 300 / 300 = 1
          2. 600 / 300 = 2
          3. 1200 / 300 = 4

          上面計(jì)算得到的 1、 2、 4 即是算出的有效的像素密度,換算成和 x 描述符等價(jià)的值 。這里 600w 算出的 2 即滿(mǎn)足 dpr = 2 的情況,選擇此張圖。

          當(dāng)前屏幕 dpr = 3 ,CSS 寬度為 414px

          當(dāng)前屏幕 CSS 寬度為 414px,則圖片 CSS 寬度仍為 300px。再計(jì)算一次:

          1. 300 / 300 = 1
          2. 600 / 300 = 2
          3. 1200 / 300 = 4

          因?yàn)?dpr = 3,2 已經(jīng)不滿(mǎn)足了,則此時(shí)會(huì)選擇 1200w 這張圖。

          當(dāng)前屏幕 dpr = 1 ,CSS 寬度為 1920px

          當(dāng)前屏幕 CSS 寬度為 1920px,則圖片 CSS 寬度變?yōu)榱?600px。再計(jì)算一次:

          1. 300 / 600 = .5
          2. 600 / 600 = 1
          3. 1200 / 600 = 2

          因?yàn)?dpr = 1,所以此時(shí)會(huì)選擇 600w 對(duì)應(yīng)的圖片。

          具體的可以試下這個(gè) Demo:CodePen Demo -- srcset屬性配合w寬度描述符配合sizes屬性[11]

          此方案的意義在于考慮到了響應(yīng)性布局的復(fù)雜性與屏幕的多樣性,利用上述規(guī)則,可以一次適配 PC 端大屏幕和移動(dòng)端高清屏,一箭多雕。

          嗯,總結(jié)一下,在實(shí)現(xiàn)響應(yīng)式圖像時(shí),我們同時(shí)使用?srcset?和?sizes?屬性。它們的作用是:

          • srcset:定義多個(gè)不同寬度的圖像源,讓瀏覽器在 HTML 解析期間選擇最合適的圖像源
          • sizes:定義圖像元素在不同的視口寬度時(shí),可能的大小值

          有了這些屬性后,瀏覽器就會(huì)根據(jù) srcset/size 來(lái)創(chuàng)建一個(gè)分辨率切換器的響應(yīng)式圖片,可以在不同的分辨率的情況下,提供相同尺寸的圖像,或者在不同的視圖大小的情況下,提供不同尺寸大小的圖像。

          本章總結(jié)

          本章節(jié)一共列舉了 5 種實(shí)現(xiàn)響應(yīng)式圖片,適配不同屏幕大小,不同 DPR 的方式,它們分別是:

          1. 無(wú)腦多倍圖的方式
          2. DRP 媒體查詢(xún)
          3. CSS Background 中的使用?image-set
          4. srcset 配合 1x 2x 像素密度描述符
          5. srcset 屬性配合 sizes 屬性 w 寬度描述符

          合理使用它們,可以有效的為不同屏幕,提供最為恰當(dāng)?shù)膱D片資源,在保證用戶(hù)體驗(yàn)的同時(shí),盡可能節(jié)省帶寬。

          它們各有優(yōu)缺點(diǎn),可以根據(jù)自己實(shí)際的業(yè)務(wù)場(chǎng)景,選取合適相對(duì)成本最低的方案,并且適當(dāng)?shù)呐浜?Autoprefixer 以及一些 PostCSS 等工具,簡(jiǎn)化代碼量。

          圖片的寬高比、裁剪與縮放

          OK,下面進(jìn)入到我們的第三個(gè)模塊,圖片的寬高比、裁剪與縮放。我們會(huì)介紹 4 個(gè)新的特性:

          • aspect-ratio
          • object-fit
          • object-position
          • image-rendering

          使用?aspect-ratio?避免布局偏移

          很多時(shí)候,只能使用固定尺寸大小的圖片,我們的布局可能是這樣:

          6667f5e0cf259dde1fa6e05c7764859b.webp

          對(duì)應(yīng)的布局:

              <ul?class="g-container">
          ????<li>
          ????????<img?src="http://placehold.it/150x100">
          ????????<p>圖片描述</p>
          ????</li>
          </ul>
              ul?li?img?{
          ????width:?150px;
          }

          當(dāng)然,萬(wàn)一假設(shè)后端接口出現(xiàn)一張非正常大小的圖片,上述不加保護(hù)的布局就會(huì)出問(wèn)題:

          24967f43ad7f970ee59626393e758072.webp

          所以對(duì)于圖片,我們總是建議同時(shí)寫(xiě)上高和寬,避免因?yàn)閳D片尺寸錯(cuò)誤帶來(lái)的布局問(wèn)題:

              ul?li?img?{
          ????width:?150px;
          ????height:?100px;
          }

          同時(shí),給?<img>?標(biāo)簽同時(shí)寫(xiě)上高寬,可以在圖片未加載之前提前占住位置,避免圖片從未加載狀態(tài)到渲染完成狀態(tài)高寬變化引起的重排問(wèn)題。

          當(dāng)然,到今天,我們還可以使用?aspect-ratio?設(shè)定圖片的高寬比。

          aspect-ratio?CSS 屬性為容器規(guī)定了一個(gè)期待的寬高比,這個(gè)寬高比可以用來(lái)計(jì)算自動(dòng)尺寸以及為其他布局函數(shù)服務(wù)。

          像是上面的代碼,我們就可以替換成:

              ul?li?img?{
          ????width:?150px;
          ????aspect-ratio:?3?/?2;
          }

          當(dāng)然,有的時(shí)候,我們的布局是響應(yīng)式動(dòng)態(tài)在變化的,容器的寬度也是不確定的,因此,有了?aspect-ratio?之后,我們的寫(xiě)法就可以更佳的舒服。

              ul?li?img?{
          ????width:?100%;
          ????aspect-ratio:?3?/?2;
          }

          這里,容器基于 Flex 彈性布局或者響應(yīng)式布局,其寬度是不固定的,但是圖片的寬高比是固定的,使用?aspect-ratio: 3 / 2?就能非常好的適配這種情況。

          我們借助了 aspect-ratio 這個(gè) CSS 中較新的屬性來(lái)始終自動(dòng)獲得正確的寬高比,無(wú)論其父元素的寬度如何變化。

          當(dāng)然,aspect-ratio?不僅僅只是能運(yùn)用在這里,在?aspect-ratio?出現(xiàn)之前,我們只能通過(guò)一些其它的 Hack 方式,譬如設(shè)置?padding-top?等方式模擬固定的寬高比。在?aspect-ratio?之后,我們終于有了設(shè)定容器固定寬高比的能力。

          object-fit?避免圖片拉伸

          當(dāng)然,限制高寬也會(huì)出現(xiàn)問(wèn)題,譬如圖片被拉伸了,非常的難看:

          b66ee085260c3a4bebfd8ab0d275be35.webp

          這個(gè)時(shí)候,我們可以借助?object-fit,它能夠指定可替換元素的內(nèi)容(也就是圖片)該如何適應(yīng)它的父容器的高寬。

              ul?li?img?{
          ????width:?150px;
          ????aspect-ratio:?3?/?2;
          ????object-fit:?cover;
          }

          利用?object-fit: cover,使圖片內(nèi)容在保持其寬高比的同時(shí)填充元素的整個(gè)內(nèi)容框。

          a9e8f83971215b07fa0c2bda04f3d718.webp

          object-fit?的取值有?fillnonecontaincover,與?background-size?類(lèi)似,可以類(lèi)比記憶。

          也可以看看這張圖,很易于理解:

          5dc8a890b75d7ad48be5e76353ba1806.webp

          object-fit?還有一個(gè)配套屬性?object-position,它可以控制圖片在其內(nèi)容框中的位置。(類(lèi)似于?background-position),默認(rèn)是?object-position: 50% 50%,如果你不希望圖片居中展示,可以使用它去改變圖片實(shí)際展示的 position。

              ul?li?img?{
          ????width:?150px;
          ????aspect-ratio:?3?/?2;
          ????object-fit:?cover;
          ????object-position:?50%?100%;
          }
          b1d53c2f3e09dad11345f0354230db18.webp

          像是這樣,object-position: 100% 50%?指明從底部開(kāi)始展示圖片。這里有一個(gè)很好的 Demo 可以幫助你理解?object-position

          CodePen Demo -- Object position [13]

          使用?image-rendering?設(shè)置圖片縮放算法

          相對(duì)于上面幾個(gè)新特性,image-rendering?會(huì)更為冷門(mén)。

          很多時(shí)候,我們?cè)O(shè)置一個(gè)圖片在頁(yè)面上的展示大小為?200px x 200px,但是圖片的原始尺寸可能是?800px x 800px,也可能是?50px x 50px

          這個(gè)時(shí)候,我們就可以利用?image-rendering,設(shè)置圖片在縮放狀態(tài)下的展示算法。

          image-rendering?在特定的場(chǎng)景下,能夠起到奇效。

          來(lái)看這樣一個(gè)有意思的 DEMO,假設(shè)我們有這樣一個(gè)原圖效果,它是一個(gè)二維碼,大小為?100px x 100px

          如果我們將它放大,放到很大,明顯,這個(gè)二維碼會(huì)失真,像是這樣:

          OK,在這種放大失真的情況想,可以使用?image-rendering?改變圖片縮放算法,這里我們?cè)囈幌?image-rendering: pixelated

              .img?{
          ??image-rendering:?pixelated;
          }

          效果變化,如下圖所示:

          可以看到,image-rendering: pixelated?處理過(guò)的圖像,竟然變得如此清晰!

          CodePen Demo -- QrCode Image-rendering demo [14]

          來(lái)看看?image-rendering?的幾個(gè)取值:

          • image-rendering: auto:自 Gecko 1.9(Firefox 3.0)起,Gecko 使用雙線性(bilinear)算法進(jìn)行重新采樣(高質(zhì)量)。
          • image-rendering: smooth:使用能最大化圖像客觀觀感的算法來(lái)縮放圖像
          • image-rendering: high-quality:與 smooth 相同,但更傾向于高質(zhì)量的縮放。
          • image-rendering: crisp-edges:必須使用可有效保留對(duì)比度和圖像中的邊緣的算法來(lái)對(duì)圖像進(jìn)行縮放,并且,該算法既不會(huì)平滑顏色,又不會(huì)在處理過(guò)程中為圖像引入模糊。合適的算法包括最近鄰居(nearest-neighbor)算法和其他非平滑縮放算法,比如 2×SaI 和 hqx-* 系列算法。此屬性值適用于像素藝術(shù)作品,例如一些網(wǎng)頁(yè)游戲中的圖像。
          • image-rendering: pixelated:放大圖像時(shí),使用最近鄰居算法,因此,圖像看著像是由大塊像素組成的。縮小圖像時(shí),算法與 auto 相同。

          雖然規(guī)范定義了挺多值,但是實(shí)際上,現(xiàn)代瀏覽器基本暫時(shí)只支持:autopixelated、以及?-webkit-optimize-contrast(Chrome 下的 smooth)。

          看描述都會(huì)挺懵逼的,實(shí)際使用的時(shí)候,最好每個(gè)都試一下驗(yàn)證一下效果。總結(jié)而言,image-rendering?的作用是在圖像縮放時(shí),提供不一樣的渲染方式,讓圖片的展示形態(tài)更為多樣化,或者說(shuō)是盡可能的去減少圖片的失真帶來(lái)的信息損耗

          我們?cè)倏匆粋€(gè) DEMO,原圖如下(例子來(lái)源于 W3C 規(guī)范文檔):

          20c3def99d5fd95f6447ad486d07fcfa.webp

          實(shí)際效果:

          72133c66d90e363385be51b716ab36f4.webp

          當(dāng)然,看上去?pixelated?的效果挺好,這是由于這是一張偏向于矢量的圖片,細(xì)節(jié)不多,對(duì)于高精度的人物圖,就不太適用于?pixelated,容易把圖片馬賽克化。

          真正規(guī)范希望的在放大后讓圖片盡可能不失真的?crisp-edges?效果,目前暫時(shí)沒(méi)有得到瀏覽器的實(shí)現(xiàn)。后面可以期待一下。

          CodePen Demo -- Image-rendering demo [15]

          本章總結(jié)

          這一章,我們介紹了 4 個(gè)較新的 CSS 特性:

          • aspect-ratio:控制容器的寬高比,避免產(chǎn)生布局偏移及抖動(dòng)
          • object-fit:設(shè)定內(nèi)容應(yīng)該如何適應(yīng)到其使用高度和寬度確定的框,避免圖片拉伸
          • object-position:基于?object-fit,設(shè)置圖片實(shí)際展示的 position 范圍
          • image-rendering:控制圖片在縮放狀態(tài)下的展示算法

          合理利用它們,可以給用戶(hù)在圖片上以更好的體驗(yàn)。

          懶加載/異步圖像解碼方案

          繼續(xù)第四章。本章節(jié),我們來(lái)討論下圖片的懶加載與異步圖像解碼方案。

          圖片的懶加載

          懶加載是一種網(wǎng)頁(yè)性能優(yōu)化的常見(jiàn)方式,它能極大的提升用戶(hù)體驗(yàn)。到今天,現(xiàn)在一張圖片超過(guò)幾 M 已經(jīng)是常見(jiàn)事了。如果每次進(jìn)入頁(yè)面都需要請(qǐng)求頁(yè)面上的所有的圖片資源,會(huì)較大的影響用戶(hù)體驗(yàn),對(duì)用戶(hù)的帶寬也是一種極大的損耗。

          所以,圖片懶加載的意義即是,當(dāng)頁(yè)面未滾動(dòng)到相應(yīng)區(qū)域,該區(qū)域內(nèi)的圖片資源(網(wǎng)絡(luò)請(qǐng)求)不會(huì)被加載。反之,當(dāng)頁(yè)面滾動(dòng)到相應(yīng)區(qū)域,相關(guān)圖片資源的請(qǐng)求才會(huì)被發(fā)起。

          在過(guò)去,我們通常都是使用 JavaScript 方案進(jìn)行圖片的懶加載。而今天,我們?cè)趫D片的懶加載實(shí)現(xiàn)上,有了更多不一樣的選擇。

          JavaScript 方案實(shí)現(xiàn)圖片的懶加載

          首先,回顧一下過(guò)往最常見(jiàn)的,使用 JavaScript 方案實(shí)現(xiàn)圖片的懶加載。

          通過(guò) JavaScript 實(shí)現(xiàn)的懶加載,主要是兩種方式:

          1. 監(jiān)聽(tīng) onscroll 事件,通過(guò)?getBoundingClientRect?API 獲取元素圖片距離視口頂部的距離,配合當(dāng)前可視區(qū)域的位置實(shí)現(xiàn)圖片的懶加載
          2. 通過(guò) HTML5 的?IntersectionObserver?API,Intersection Observer(交叉觀察器)[4]?配合監(jiān)聽(tīng)元素的?isIntersecting?屬性,判斷元素是否在可視區(qū)內(nèi),能夠?qū)崿F(xiàn)比監(jiān)聽(tīng) onscroll 性能更佳的圖片懶加載方案

          但是,JavaScript 方案的一個(gè)劣勢(shì)在于,不管如何,需要引入一定量的 JavaScript 代碼,進(jìn)行一定量的運(yùn)算。

          到今天,其實(shí)我們有更多的其他便捷的方式去實(shí)現(xiàn)圖片的懶加載。

          使用?content-visibility: auto?實(shí)現(xiàn)圖片內(nèi)容的延遲渲染

          首先,介紹一個(gè)非常有用,但是相對(duì)較為冷門(mén)的屬性 --?content-visibility

          content-visibility:屬性控制一個(gè)元素是否渲染其內(nèi)容,它允許用戶(hù)代理(瀏覽器)潛在地省略大量布局和渲染工作,直到需要它為止。

          利用?content-visibility?的特性,我們可以實(shí)現(xiàn)如果該元素當(dāng)前不在屏幕上,則不會(huì)渲染其后代元素

          假設(shè)我們有這樣一個(gè) DEMO:

              <div?class="g-wrap">
          ????//?模塊?1
          ????<div?class="paragraph">
          ????????<p>Lorem?Start!</p>???
          ????????<img?src="https://s1.ax1x.com/2023/02/20/pSX1xMV.png"?alt=""?/>
          ????????<p>Lorem?End!</p>??
          ????</div>
          ????//?模塊?2
          ????<div?class="paragraph">
          ????????<p>Lorem?Start!</p>???
          ????????<img?src="https://s1.ax1x.com/2023/02/20/pSX1xMV.png"?alt=""?/>
          ????????<p>Lorem?End!</p>??
          ????</div>
          ????//?...?連續(xù)幾十個(gè)上述類(lèi)似的結(jié)構(gòu)
          </div>

          只需要給需要延遲(實(shí)時(shí))渲染的元素,設(shè)置簡(jiǎn)單的 CSS 樣式:

              .paragraph?{
          ????content-visibility:?auto;
          }

          我們來(lái)看一下,設(shè)置了?content-visibility: auto?與沒(méi)設(shè)置的區(qū)別。

          如果,不添加上述的?content-visibility: auto?代碼,頁(yè)面的滾動(dòng)條及滾動(dòng)效果如下:

          12e761caaf0a424b505d0f33385fa5db.webp

          那么,在添加了?content-visibility: auto?之后,注意觀察頁(yè)面的滾動(dòng)條及滾動(dòng)效果:

          6065722cc90e41e531a91734987cba46.webp

          可以看到滾動(dòng)條在向下滾動(dòng)在不斷的抽搐,這是由于下面不在可視區(qū)域內(nèi)的內(nèi)容,一開(kāi)始是沒(méi)有被渲染的,在每次滾動(dòng)的過(guò)程中,才逐漸渲染,以此來(lái)提升性能。

          Codepen Deom -- content-visibility: auto Image Load Demo [17]

          content-visibility: auto?VS 圖片懶加載

          當(dāng)然,其實(shí)使用?content-visibility: auto?并不能真正意義上實(shí)現(xiàn)圖片的懶加載。

          這是因?yàn)椋幢惝?dāng)前頁(yè)面可視區(qū)域外的內(nèi)容未被渲染,但是圖片資源的 HTTP/HTTPS 請(qǐng)求,依然會(huì)在頁(yè)面一開(kāi)始被觸發(fā)!

          因此,這也得到了一個(gè)非常重要的結(jié)論:

          content-visibility: auto?無(wú)法直接替代圖片懶加載,設(shè)置了?content-visibility: auto?的元素在可視區(qū)外只是未被渲染,但是其中的靜態(tài)資源仍舊會(huì)在頁(yè)面初始化的時(shí)候被全部加載。因此,它更像是一個(gè)虛擬列表的替代方案。

          關(guān)于?content-visibility?本文限于篇幅,沒(méi)有完全展開(kāi),但是它是一個(gè)非常有意思且對(duì)渲染性能有幫助的屬性,完整的教程,你可以看我的這篇文章 --?使用 content-visibility 優(yōu)化渲染性能[18]

          使用?loading=lazy?HTML 屬性實(shí)現(xiàn)圖片懶加載

          OK,content-visibility?很不錯(cuò),但是略有瑕疵。但是,我們還有其他方式。

          HTML5 新增了一個(gè)?loading?屬性。

          到今天,除了 IE 系列瀏覽器,目前都支持通過(guò)?loading?屬性實(shí)現(xiàn)延遲加載。此屬性可以添加到?<img>?元素中,也可以添加到?<iframe>?元素中。

          屬性的值為?loading=lazy?會(huì)告訴瀏覽器,如果圖像位于可視區(qū)時(shí),則立即加載圖像,并在用戶(hù)滾動(dòng)到它們附近時(shí)獲取其他圖像。

          我們可以像是這樣使用它:

              
                <img?src="xxx.png"?loading="lazy">
                

          這樣,便可以非常便捷的實(shí)現(xiàn)圖片的懶加載,省去了添加繁瑣的 JavaScript 代碼的過(guò)程

          看看?loading=lazy?到今天(2023-02-26)的兼容性,還是非常不錯(cuò)的:

          255ed02b4f90a7870f90acccbe39ed6f.webp

          使用?decoding=async?實(shí)現(xiàn)圖片的異步解碼

          除了?loading=lazy,HTML5 還新增了一個(gè)非常有意思的屬性增強(qiáng)圖片的用戶(hù)體驗(yàn)。那就是?decoding?屬性。

          HTMLImageElement[19]?接口的?decoding?屬性用于告訴瀏覽器使用何種方式解析圖像數(shù)據(jù)。

          它的可選取值如下:

          • sync: 同步解碼圖像,保證與其他內(nèi)容一起顯示。
          • async: 異步解碼圖像,加快顯示其他內(nèi)容。
          • auto: 默認(rèn)模式,表示不偏好解碼模式。由瀏覽器決定哪種方式更適合用戶(hù)。

          上文其實(shí)也提及了,瀏覽器在進(jìn)行圖片渲染展示的過(guò)程中,是需要對(duì)圖片文件進(jìn)行解碼的,這一個(gè)過(guò)程快慢與圖片格式有關(guān)。

          而如果我們不希望圖片的渲染解碼影響頁(yè)面的其他內(nèi)容的展示,可以使用?decoding=async?選項(xiàng),像是這樣:

              
                <img?src="xxx.png"?decoding="async">
                

          這樣,瀏覽器便會(huì)異步解碼圖像,加快顯示其他內(nèi)容。這是圖片優(yōu)化方案中可選的一環(huán)。

          同樣的,我們來(lái)看看到今天(2023-02-26),decoding="async"?的兼容性,整體還是非常不錯(cuò)的,作為漸進(jìn)增強(qiáng)方案使用,是非常好的選擇。

          701246f818954ca287976b8f9024e79f.webp

          實(shí)際檢驗(yàn)?loading=lazy?與?decoding=async?效果

          OK,下面我們制作一個(gè)簡(jiǎn)單的 DEMO,試一下?loading=lazy?與?decoding=async?的效果。

          我們準(zhǔn)備一個(gè)擁有 339 個(gè)圖片的 HTML 頁(yè)面,每個(gè)圖片文件的 src 大小不一。

              <div?class="g-container">
          ????<img?src="image1.jpeg">
          ????<img?src="image2.jpeg">
          ????//?...?339?個(gè)
          </div>

          CSS 的設(shè)置也很重要,由于是純圖片頁(yè)面,如果不給圖片設(shè)置默認(rèn)高寬,最頁(yè)面刷新的一瞬間,<img>?元素的高寬都是 0,會(huì)導(dǎo)致所有?<img>?元素都在可視區(qū)內(nèi),所以,我們需要給?<img>?設(shè)置一個(gè)默認(rèn)的高寬:

              img?{
          ????margin:?8px;
          ????width:?300px;
          ????height:?200px;
          ????object-fit:?cover;
          }

          這樣,再不添加?loading=lazy?與?decoding=async?的狀態(tài)下,看看?Network?的表現(xiàn):

          d77be8ab8b46ba35b07e297bf2e03f1d.webp

          我這里沒(méi)有模擬弱網(wǎng)環(huán)境,網(wǎng)速非常快,可以看到,發(fā)送了 339 個(gè)圖片資源請(qǐng)求,也就是全部的圖片資源在頁(yè)面加載的過(guò)程中都請(qǐng)求了,頁(yè)面?Load?事件完成的時(shí)間為 1.28s。

          好,我們給所有的圖片元素,添加上?loading=lazy?與?decoding=async

              <div?class="g-container">
          ????<img?src="image1.jpeg"?loading="lazy"?decoding="async">
          ????<img?src="image2.jpeg"?loading="lazy"?decoding="async">
          ????//?...?339?個(gè)
          </div>

          看看效果:

          51573616177f752337156f73f1cdfe1e.webp

          可以看到,這一次只發(fā)送了 17 個(gè)圖片資源請(qǐng)求,頁(yè)面?Load?事件完成的時(shí)間為 26ms。

          優(yōu)化前 優(yōu)化后
          1.28s 26 ms

          1.28s 到 26ms,效果是非常明顯的,如果是弱網(wǎng)環(huán)境,對(duì)首屏加載性能的提升,會(huì)更為明顯

          當(dāng)然,實(shí)際我測(cè)試的過(guò)程也,也單獨(dú)試過(guò)?decoding="async"?的作用,只是由于是純圖片頁(yè)面,效果不那么明顯。感興趣的同學(xué),可以自行嘗試。

          本章總結(jié)

          在本章節(jié)中,我們介紹了不同的方式實(shí)現(xiàn)圖片的懶加載、延遲渲染、異步解碼,它們分別是:

          1. 通過(guò) onscroll 事件與?getBoundingClientRect?API 實(shí)現(xiàn)圖片的懶加載方案
          2. 通過(guò) Intersection Observer(交叉觀察器)實(shí)現(xiàn)比監(jiān)聽(tīng) onscroll 性能更佳的圖片懶加載方案
          3. 通過(guò)?content-visibility: auto?實(shí)現(xiàn)圖片資源的延遲渲染
          4. 通過(guò)?loading=lazy?HTML 屬性實(shí)現(xiàn)圖片懶加載
          5. 通過(guò)?decoding=async?HTML 屬性實(shí)現(xiàn)圖片的異步解碼

          圖片資源的容錯(cuò)及可訪問(wèn)性處理

          OK,最后一個(gè)章節(jié),我們簡(jiǎn)單聊一聊圖片資源的容錯(cuò)及可訪問(wèn)性處理。

          圖片的可訪問(wèn)性處理

          可訪問(wèn)性(A11Y),在我們的網(wǎng)站中,屬于非常重要的一環(huán),但是大部分同學(xué)都容易忽視它。

          在一些重交互、重邏輯的網(wǎng)站中,我們需要考慮用戶(hù)的使用習(xí)慣、使用場(chǎng)景,從高可訪問(wèn)性的角度考慮,譬如假設(shè)用戶(hù)沒(méi)有鼠標(biāo),僅僅使用鍵盤(pán),能否順暢的使用我們的網(wǎng)站?

          非常重要的一點(diǎn)是, 提高可訪問(wèn)性也能讓普通用戶(hù)更容易理解 Web 內(nèi)容

          基于?Usability & Web Accessibility - image[20]

          對(duì)于圖像信息,我們需要大致遵循如下可訪問(wèn)性原則:

          • 所有有意義的 img 元素必須有 alt 屬性
          • 提供替代 alt 屬性的其他方式
          • 使用輔助技術(shù)隱藏裝飾圖像

          第一點(diǎn)非常好理解,所有的有意義的圖片元素都必須要提供?alt?屬性。

          第二點(diǎn)比較有意思,在 A11Y 中,其實(shí)有一套?WAI-ARIA 標(biāo)準(zhǔn)[21]。WAI-ARIA 是一個(gè)為殘疾人士等提供無(wú)障礙訪問(wèn)動(dòng)態(tài)、可交互Web內(nèi)容的技術(shù)規(guī)范。

          簡(jiǎn)單來(lái)說(shuō),它提供了一些屬性,增強(qiáng)標(biāo)簽的語(yǔ)義及行為:

          • 可以使用 tabindex 屬性控制元素是否可以聚焦,以及它是否/在何處參與順序鍵盤(pán)導(dǎo)航
          • 可以使用 role 屬性,來(lái)標(biāo)識(shí)元素的語(yǔ)義及作用,譬如使用?<div id="saveChanges" tabindex="0" role="button">Save</div>來(lái)模擬一個(gè)按鈕
          • 還有大量的?aria-*?屬性,表示元素的屬性或狀態(tài),幫助我們進(jìn)一步地識(shí)別以及實(shí)現(xiàn)元素的語(yǔ)義化,優(yōu)化無(wú)障礙體驗(yàn)

          上述第二點(diǎn),提供替代 alt 屬性的其他方式?的含義就是使用 WAR-ARIA 規(guī)范提供的諸如?aria-label?和?aria-labelledby?屬性為圖像提供可訪問(wèn)的名稱(chēng)。

          當(dāng)存在這些屬性時(shí),輔助技術(shù)(屏幕閱讀器)將忽略圖像的?alt?屬性并讀取 ARIA 標(biāo)簽。

          而第三點(diǎn),使用輔助技術(shù)隱藏裝飾圖像,又是什么意思呢?

          上面第一點(diǎn)?所有有意義的 img 元素必須有 alt 屬性,反過(guò)來(lái)說(shuō),頁(yè)面上也會(huì)存在無(wú)意義的裝飾性的圖片,這些圖片內(nèi)容對(duì)輔助技術(shù)(屏幕閱讀器)而言,其實(shí)是可以忽略的。

          對(duì)于沒(méi)有任何功能或信息內(nèi)容的裝飾圖像,可以通過(guò)多種方式對(duì)屏幕閱讀器隱藏:

          • 使用空的?alt?屬性
          • 使用 ARIA 屬性?role="presentation"?標(biāo)明圖片元素是裝飾可忽略圖片
          • 使用 CSS background 的方式呈現(xiàn)這些圖片

          alt 不要與 title 混淆

          OK,下面來(lái)講一些有意思的細(xì)節(jié)內(nèi)容。

          有一個(gè)非常基礎(chǔ)的知識(shí),簡(jiǎn)單過(guò)一下,也就是圖片元素中,alt?與?title?的差異:

          • 圖片中的?alt?屬性是在圖片不能正常顯示時(shí)出現(xiàn)的文本提示。
          • 圖片中的?title?屬性是在鼠標(biāo)在移動(dòng)到元素上的文本提示。

          正確使用 alt 屬性

          對(duì)于使用屏幕閱讀器的用戶(hù)而言,圖片是無(wú)法正常展示或者被的瀏覽的,基于此,我們需要利用好?alt?屬性,或者是上述的aria-label?和?aria-labelledby?屬性。

          那么,這些屬性?xún)?nèi)的內(nèi)容應(yīng)該填充什么呢?我們需要基于圖片的功能加以區(qū)分:

          • 信息性圖像[22]:以圖形方式表示概念和信息的圖像,通常是圖片、照片和插圖。alt?替代文本應(yīng)該至少是一個(gè)簡(jiǎn)短的描述,傳達(dá)圖像所呈現(xiàn)的基本信息。

          • 裝飾性圖像[23]:當(dāng)圖像的唯一目的是為頁(yè)面添加視覺(jué)裝飾,而不是傳達(dá)對(duì)理解頁(yè)面很重要的信息時(shí),如上述所言,使用空的 alt,譬如?alt=""

          • 功能圖像[24]:用作鏈接或按鈕的圖像的替代文本應(yīng)該描述鏈接或按鈕的功能,而不是視覺(jué)圖像。此類(lèi)圖像的示例是表示打印功能的打印機(jī)圖標(biāo)或提交表單的按鈕。

          • 文本圖像[25]:可讀文本有時(shí)會(huì)出現(xiàn)在圖像中。如果圖片不是徽標(biāo),請(qǐng)避免圖片中出現(xiàn)文字。但是,如果使用文本圖像,替代文本應(yīng)包含與圖像中相同的詞。

          • 圖形和圖表等復(fù)雜圖像:為了傳達(dá)數(shù)據(jù)或詳細(xì)信息,提供與圖像中提供的數(shù)據(jù)或信息等效的完整文本作為替代文本。[26]

          • 圖像組[27]:如果多張圖像傳達(dá)一條信息,則一張圖像的替代文本應(yīng)傳達(dá)整組信息。

          • 圖像映射[28]:包含多個(gè)可點(diǎn)擊區(qū)域的圖像的替代文本應(yīng)該為鏈接集提供整體上下文。此外,每個(gè)可單獨(dú)點(diǎn)擊的區(qū)域都應(yīng)該有替代文本來(lái)描述鏈接的目的或目的地。

          其實(shí)?alt?的學(xué)問(wèn)是非常之多的,如果我們的頁(yè)面能做到這一點(diǎn),那真的算是從根上開(kāi)始思考,開(kāi)始優(yōu)化用戶(hù)體驗(yàn)。

          img 元素與 background 元素的取舍

          OK,那么,講到這里,還有一個(gè)有意思的點(diǎn)就很自然的應(yīng)該被提及。

          那就是我們應(yīng)該什么時(shí)候使用?<img>?元素,什么時(shí)候使用?background?內(nèi)嵌圖片?

          我們可以從性能功能兩個(gè)方面進(jìn)行考慮:

          類(lèi)型 img backgroud-image
          圖層位置 前景 背景
          默認(rèn)初始尺寸 不定 固定
          是否會(huì)產(chǎn)生回流重繪 會(huì) 不會(huì)
          圖片加載失敗 可以觸發(fā)元素的 onerror 事件,展示 alt 屬性 無(wú)法有效設(shè)置異常處理場(chǎng)景
          使用場(chǎng)景 Logo、產(chǎn)品圖片、廣告圖片 裝飾性無(wú)語(yǔ)義內(nèi)容等

          其實(shí)性能上并不是核心考慮的點(diǎn),因?yàn)樯衔奈覀円仓v到了在今天可以大規(guī)模使用是?loading="lazy"?屬性,圖片可以進(jìn)行原生支持的懶加載。

          我們?cè)诳紤]選取?<img>?還是?backgroud-image?的時(shí)候,更多的還是從圖片功能上進(jìn)行考慮。一般來(lái)說(shuō),作為修飾的且無(wú)語(yǔ)義的裝飾性圖片選擇使用?background-image,而比較重要的與網(wǎng)頁(yè)內(nèi)容相關(guān)的就使用?<img>?標(biāo)簽。

          由于有語(yǔ)義的圖片使用?<img>?展示,它的一個(gè)好處在于,當(dāng)圖片加載失敗的時(shí)候,可以觸發(fā)元素的 onerror 事件,我們可以有效的利用這一點(diǎn),對(duì)圖片進(jìn)行異常處理。

          圖片的異常處理

          當(dāng)圖片鏈接掛了,加載失敗了,我們比較好的處理方式應(yīng)該是怎么樣呢?

          處理的方式有很多種。在張?chǎng)涡窭蠋煹倪@篇文章中 --?圖片加載失敗后CSS樣式處理最佳實(shí)踐[29]?有一個(gè)不錯(cuò)的實(shí)踐。

          核心思路為:

          1. 利用圖片加載失敗,觸發(fā)?<img>?元素的?onerror?事件,給加載失敗的?<img>?元素新增一個(gè)樣式類(lèi)
          2. 利用新增的樣式類(lèi),配合?<img>?元素的偽元素,在展示默認(rèn)兜底圖的同時(shí),還能一起展示?<img>?元素的?alt?信息
              
                <img?src="test.png"?alt="Alt?Info"?onerror="this.classList.add('error');">
                
              img.error?{
          ????position:?relative;
          ????display:?inline-block;
          }

          img.error::before?{
          ????content:?"";
          ????/**?定位代碼?**/
          ????background:?url(error-default.png);
          }

          img.error::after?{
          ????content:?attr(alt);
          ????/**?定位代碼?**/
          }

          我們利用偽元素?before?,加載默認(rèn)錯(cuò)誤兜底圖,利用偽元素?after,展示圖片的?alt?信息:

          e9c56eacbba6fa6b4708ea2439f8a06a.webp

          OK,到此,完整的對(duì)圖片的處理就算完成了,這也比較好的闡述了為什么,對(duì)有語(yǔ)義,有?alt?信息的圖片,我們應(yīng)該使用?<img>?元素來(lái)實(shí)現(xiàn)。這是因?yàn)椋覀兛梢栽阱e(cuò)誤發(fā)生的時(shí)候,比較好的對(duì)圖片進(jìn)行兜底展示,讓用戶(hù)直觀的能夠看到 alt 內(nèi)容。

          完整的 Demo 你可以戳這里看看:

          CodePen Demo -- 圖片處理 [30]

          當(dāng)然,上述方案存在兩個(gè)小問(wèn)題:

          1. 對(duì)于每一個(gè)?<img>?元素,我們都需要寫(xiě)一段?onerror="this.classList.add('error');"?代碼,有點(diǎn)重復(fù)。因此,這個(gè)工作也可以交給 JavaScript 全局性的完成,并且,我們可能需要判斷?alt?的值是否為空,在為空時(shí),使用默認(rèn)圖片 alt 兜底文案。
          2. 早年間,<img>?等替換元素是沒(méi)有偽元素的,后面 Chrome/Firefox 瀏覽器逐漸支持了當(dāng),<img>?的 src 拉取失敗時(shí),支持?<img>?元素的偽元素展示,這才有了上述的方案,但是,目前 Safari 仍不支持這個(gè)特性,所以,在 Safari 下,我們可能得到如下的結(jié)果:

          97db34d39ccb008bc859307e9d9e51c6.webp

          效果仍然還是 OK 的,只是沒(méi)有了兜底圖的展示,在實(shí)際使用過(guò)程中,需要知道這一點(diǎn)。

          最后總結(jié)

          本章節(jié),對(duì)圖片資源的容錯(cuò)及可訪問(wèn)性處理進(jìn)行了闡述。核心內(nèi)容在于:

          1. 對(duì)于圖像信息,我們需要大致遵循如下可訪問(wèn)性原則:
          • 所有有意義的 img 元素必須有 alt 屬性
          • 提供替代 alt 屬性的其他方式
          • 使用輔助技術(shù)隱藏裝飾圖像
          正確使用 alt 屬性,了解不同場(chǎng)景下 alt 應(yīng)該填充什么內(nèi)容 img 元素與 background 元素的取舍 圖片異常處理的最佳實(shí)踐

          至此,整個(gè)現(xiàn)代圖片性能優(yōu)化及體驗(yàn)優(yōu)化指南到此就圓滿(mǎn)結(jié)束,整個(gè)系列的文章囊括了非常多的新的規(guī)范及特性,需要大家在實(shí)踐中根據(jù)實(shí)際情況靈活選取使用。

          同時(shí),我們也應(yīng)該能看到,前端技術(shù)僅僅在這一小個(gè)領(lǐng)域,都在不斷的迭代創(chuàng)新。雖然很難,還是需要不斷充實(shí)自己跟上新的潮流。共勉。

          最后

          OK,本文到此結(jié)束,希望本文對(duì)你有所幫助 :)

          想 Get 到最有意思的 CSS 資訊,千萬(wàn)不要錯(cuò)過(guò)我的公眾號(hào) --?iCSS前端趣聞???

          更多精彩 CSS 技術(shù)文章匯總在我的?Github -- iCSS[31]?,持續(xù)更新,歡迎點(diǎn)個(gè) star 訂閱收藏。

          如果還有什么疑問(wèn)或者建議,可以多多交流,原創(chuàng)文章,文筆有限,才疏學(xué)淺,文中若有不正之處,萬(wàn)望告知。

          參考資料
          由于微信公眾號(hào)排版實(shí)在過(guò)于難用,本文的參考鏈接建議點(diǎn)進(jìn)我的 PC 端原文進(jìn)行獲取,原文鏈接:https://github.com/chokcoco/iCSS/issues/229

          如果覺(jué)得還不錯(cuò),歡迎 點(diǎn)贊、收藏、轉(zhuǎn)發(fā) ??

          瀏覽 95
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  色色网站在线观看观看 | 欧美一级a做一级a做片性 | 超碰97在线免费 | 影音先锋aV成人无码电影 | 欧美成人无码片免费看A片秀色 |