天天看點

現代圖檔性能優化及體驗優化指南 - 響應式圖檔方案

作者:閃念基因

圖檔資源,在我們的業務中可謂是占據了非常大頭的一環,尤其是其對帶寬的消耗是十分巨大的。

對圖檔的性能優化及體驗優化在今天就顯得尤為重要。本文,就将從各個方面闡述,在各種新特性滿頭飛的今天,我們可以如何盡可能的對我們的圖檔資源,進行性能優化及體驗優化。

适配不同的螢幕尺寸及 DPR

下一個子產品,我們來看看圖檔資源如何更好的适配不同的螢幕尺寸。

這裡首先會涉及一個預備知識,螢幕的 DPR 值,那麼,什麼是 DPR 呢?要了解 DPR,又需要知道什麼是裝置獨立像素 以及 實體像素。

裝置獨立像素

以 iPhone6/7/8為例,這裡我們打開 Chrome 開發者工具:

現代圖檔性能優化及體驗優化指南 - 響應式圖檔方案

這裡的 375 * 667 表示的是什麼呢,表示的是裝置獨立像素(DIP),也可以了解為 CSS 像素,也稱為邏輯像素:

裝置獨立像素 = CSS 像素 = 邏輯像素

如何記憶呢?這裡使用 CSS 像素來記憶,也就是說。我們設定一個寬度為 375px 的 div,剛好可以充滿這個裝置的一行,配合高度 667px ,則 div 的大小剛好可以充滿整個螢幕。

實體像素

OK,那麼,什麼又是實體像素呢。我們到電商網站購買手機,都會看一看手機的參數,以 JD 上的 iPhone7 為例:

現代圖檔性能優化及體驗優化指南 - 響應式圖檔方案

可以看到,iPhone7 的分辨率是 1334 x 750,這裡描述的就是螢幕實際的實體像素。

實體像素,又稱為裝置像素。顯示屏是由一個個實體像素點組成的,1334 x 750 表示手機分别在垂直和水準上所具有的像素點數。通過控制每個像素點的顔色,就可以使螢幕顯示出不同的圖像,螢幕從工廠出來那天起,它上面的實體像素點就固定不變了,機關為pt。

裝置像素 = 實體像素

DPR(Device Pixel Ratio) 裝置像素比

OK,有了上面兩個概念,就可以順理成章引出下一個概念。DPR(Device Pixel Ratio) 裝置像素比,這個與我們通常說的視網膜屏(多倍屏,Retina屏)有關。

裝置像素比描述的是未縮放狀态下,實體像素和裝置獨立像素的初始比例關系。

簡單的計算公式:

DPR = 實體像素 / 裝置獨立像素

我們套用一下上面 iPhone7 的資料(取裝置的實體像素寬度與裝置獨立像素寬度進行計算):

iPhone7’s DPR = iPhone7’s 實體像素寬度 / iPhone7's 裝置獨立像素寬度 = 2

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

可以得到 iPhone7 的 dpr 為 2。也就是我們常說的視網膜螢幕。

視網膜(Retina)螢幕是蘋果公司"發明"的一個營銷術語。蘋果公司将 dpr > 1 的螢幕稱為視網膜螢幕。

現代圖檔性能優化及體驗優化指南 - 響應式圖檔方案

在視網膜螢幕中,以 dpr = 2 為例,把 4(2x2) 個像素當 1 個像素使用,這樣讓螢幕看起來更精緻,但是元素的大小本身卻不會改變:

現代圖檔性能優化及體驗優化指南 - 響應式圖檔方案

OK,我們再來看看 iPhone XS Max:

現代圖檔性能優化及體驗優化指南 - 響應式圖檔方案

它的實體像素如上圖是 2688 x 1242,

現代圖檔性能優化及體驗優化指南 - 響應式圖檔方案

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

為不同 DPR 螢幕,提供恰當的圖檔

那麼,DPR 和圖檔适配有什麼關系呢?

舉個例子,同樣的 CSS 像素大小下,螢幕如果有不同 DPR,同樣大小的圖檔渲染出來的效果不盡相同。

我們以 dpr = 3 的手機為例子,在 300 x 389 CSS 像素大小的範圍内,渲染 1倍/2倍/3倍 圖的效果如下:

現代圖檔性能優化及體驗優化指南 - 響應式圖檔方案
實際圖檔所占的實體像素為 900 x 1167。

可以看到,在高 DPR 裝置下提供隻有 CSS 像素大小的圖檔,是非常模糊的。

是以,為了在不同的 DPR 螢幕下,讓圖檔看起來都不失真,我們需要為不同 DPR 的圖檔,提供不同大小的圖檔。

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

方案一:無腦多倍圖

假設,在移動端假設我們需要一張 CSS 像素為 300 x 200 的圖像,考慮到現在已經有了 dpr = 3 的裝置,那麼要保證圖檔在 dpr = 3 的裝置下也正常高清展示,我們最大可能需要一張 900 x 600 的原圖。

這樣,不管裝置的 dpr 是否為 3,我們統一都使用 3 倍圖。這樣即使在 dpr = 1,dpr = 2 的裝置上,也能非常好的展示圖檔。

當然這樣并不可取,會造成大量帶寬的浪費。

現代浏覽器,提供了更好的方式,讓我們能夠根據裝置 dpr 的不同,提供不同尺寸的圖檔。

方案二:媒體查詢

方案二,我們可以考慮使用媒體查詢。到今天,我們可以通過相應的媒體查詢,得知目前的裝置的 DPR 值,這樣,我們就可以在對應的媒體查詢中,使用對應的圖檔。

像是這樣:

#id { 
    background: url([email protected]) 
}
@media (device-pixel-ratio: 2) {
    #id { 
        background: url([email protected]) 
    }
}
@media (device-pixel-ratio: 3) {
    #id { 
        background: url([email protected]) 
    }
}
           

這個方案的缺點在于:

  1. 要寫的代碼可能太多了,而且,可能存在一些介于 1~2,2~3 之間的 DPR 值,不好窮舉出所有場景
  2. 需要注意文法需要的相容性,需要添加字首,譬如 -webkit-min-device-pixel-ratio,當然這個可以由 autoprefixer 輔助解決

方案三:CSS 配合 image-set 文法

image-set 屬于 CSS background 中的一種文法,image-set() 函數為裝置提供最合适的圖像分辨率,它提供一組圖像選項,每個選項都有一個相關的 DPR 聲明,浏覽器将從中選擇最适合裝置的圖像進行設定。

什麼意思呢,來看看代碼:

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

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

這樣一看,作用應該很清晰了。對于支援 image-set 文法的浏覽器:

  1. 如果其裝置對應的 DPR 為 2,會選取這條 url('./[email protected]') 2x 記錄,也就是最終生效的 URL 是 './[email protected]';
  2. 如果其裝置對應的 DPR 為 3,會選取這條 url('./[email protected]') 3x 記錄,也就是最終生效的 URL 是 './[email protected]';

其中的 2x,3x 就是用于比對 DRP的。

使用 image-set 的一些痛點與媒體查詢方案類似。代碼量與相容性文法,而且難以比對所有情況。

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

簡單來說,srcset 可以根據不同的 dpr 拉取對應尺寸的圖檔:

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

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

  • 當螢幕的 dpr = 1 時,使用 images/illustration-small.png 這張圖
  • 當螢幕的 dpr = 2 時,使用 images/illustration-big.png 這張圖
  • 如果不支援 srcset 文法,src='illustration-small.png' 将會是最終的兜底方案

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

上面 1x,2x 的寫法比較容易接受易于了解。

但是,上述 3 種方案都存在統一的問題,隻考慮了 DPR,但是忽略了響應性布局的複雜性與螢幕的多樣性。

是以,規範還推出了一種方案 -- srcset 屬性配合 sizes 屬性 w 寬度描述符。

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

sizes 屬性怎麼了解呢?它定義圖像元素在不同的視口寬度時,可能的大小值。

以下面這段代碼為例子:

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

解析一下:

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

  1. 如果螢幕目前的 CSS 像素寬度大于或者等于 600px,則圖檔的 CSS 寬度為 600px
  2. 反之,則圖檔的 CSS 寬度為 300px

也就是 sizes 屬性聲明了在不同寬度下圖檔的 CSS 寬度表現。這裡可以了解為,大螢幕下圖檔寬度為 600px,小螢幕下圖檔寬度為 300px。

需要注意的是,這裡大屏、小屏下圖檔具體的寬度表現,還是需要借助媒體查詢代碼,經由 CSS 實作的

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

那麼,怎麼确定目前場景會選取哪張圖檔呢?

目前螢幕 dpr = 2 ,CSS 寬度為 375px。

目前螢幕 CSS 寬度為 375px,則圖檔 CSS 寬度為 300px。分别用上述 3 個寬度描述符的數值除以 300。

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

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

目前螢幕 dpr = 3 ,CSS 寬度為 414px。

目前螢幕 CSS 寬度為 414px,則圖檔 CSS 寬度仍為 300px。再計算一次:

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

因為 dpr = 3,2 已經不滿足了,則此時會選擇 1200w 這張圖。

目前螢幕 dpr = 1 ,CSS 寬度為 1920px。

目前螢幕 CSS 寬度為 1920px,則圖檔 CSS 寬度變為了 600px。再計算一次:

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

因為 dpr = 1,是以此時會選擇 600w 對應的圖檔。

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

此方案的意義在于考慮到了響應性布局的複雜性與螢幕的多樣性,利用上述規則,可以一次适配 PC 端大螢幕和移動端高清屏,一箭多雕。

嗯,總結一下,在實作響應式圖像時,我們同時使用 srcset 和 sizes 屬性。它們的作用是:

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

有了這些屬性後,浏覽器就會根據 srcset/size 來建立一個分辨率切換器的響應式圖檔,可以在不同的分辨率的情況下,提供相同尺寸的圖像,或者在不同的視圖大小的情況下,提供不同尺寸大小的圖像。

本章總結

本章節一共列舉了 5 種實作響應式圖檔,适配不同螢幕大小,不同 DPR 的方式,它們分别是:

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

合理使用它們,可以有效的為不同螢幕,提供最為恰當的圖檔資源,在保證使用者體驗的同時,盡可能節省帶寬。

它們各有優缺點,可以根據自己實際的業務場景,選取合适相對成本最低的方案,并且适當的配合 Autoprefixer 以及一些 PostCSS 等工具,簡化代碼量。

當然,本文隻是現代圖檔性能優化及體驗優化指南的第二篇,後續将給大家帶來圖檔在:

  • 圖檔的寬高比、裁剪與縮放展示
  • 懶加載/異步圖像解碼方案
  • 可通路性以及圖檔資源的容錯及錯誤處理

等相關知識的介紹,感興趣的可以提前關注。

最後

OK,本文到此結束,希望本文對你有所幫助 :)

更多精彩 CSS 技術文章彙總在我的 Github -- iCSS[3] ,持續更新,歡迎點個 star 訂閱收藏。

如果還有什麼疑問或者建議,可以多多交流,原創文章,文筆有限,才疏學淺,文中若有不正之處,萬望告知。

參考資料

[1]

現代圖檔性能優化及體驗優化指南 - 圖檔類型及 Picture 标簽的使用: https://juejin.cn/post/7198182873366888509

[2]

CodePen Demo -- srcset屬性配合w寬度描述符配合sizes屬性: https://codepen.io/Chokcoco/pen/WNeZvOX?editors=1100

[3]

Github -- iCSS: https://github.com/chokcoco/iCSS

作者:SbCo

來源:微信公衆号:iCSS前端趣聞

出處:https://mp.weixin.qq.com/s/sTlgjI4rOfrPRna0iLiRRA

繼續閱讀