現代圖片效能優化及體驗優化指南

2023-02-23 12:02:49

本文是系列第三篇。系列文章:

  1. 現代圖片效能優化及體驗優化指南 - 圖片型別及 Picture 標籤的使用
  2. 現代圖片效能優化及體驗優化指南 - 響應式圖片方案

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

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

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

OK,下面進入到我們的第三個模組,圖片的寬高比、裁剪與縮放。我們會介紹 4 個新的特性:

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

使用 aspect-ratio 避免佈局偏移

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

對應的佈局:

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

當然,萬一假設後端介面出現一張非正常大小的圖片,上述不加保護的佈局就會出問題:

所以對於圖片,我們總是建議同時寫上高和寬,避免因為圖片尺寸錯誤帶來的佈局問題:

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

同時,給 <img> 標籤同時寫上高寬,可以在圖片未載入之前提前佔住位置,避免圖片從未載入狀態到渲染完成狀態高寬變化引起的重排問題。

當然,到今天,我們還可以使用 aspect-ratio 設定圖片的高寬比。

aspect-ratio CSS 屬性為容器規定了一個期待的寬高比,這個寬高比可以用來計算自動尺寸以及為其他佈局函數服務。

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

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

當然,有的時候,我們的佈局是響應式動態在變化的,容器的寬度也是不確定的,因此,有了 aspect-ratio 之後,我們的寫法就可以更佳的舒服。

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

這裡,容器基於 Flex 彈性佈局或者響應式佈局,其寬度是不固定的,但是圖片的寬高比是固定的,使用 aspect-ratio: 3 / 2 就能非常好的適配這種情況。

我們藉助了 aspect-ratio 這個 CSS 中較新的屬性來始終自動獲得正確的寬高比,無論其父元素的寬度如何變化。

當然,aspect-ratio 不僅僅只是能運用在這裡,在 aspect-ratio 出現之前,我們只能通過一些其它的 Hack 方式,譬如設定 padding-top 等方式模擬固定的寬高比。在 aspect-ratio 之後,我們終於有了設定容器固定寬高比的能力。

object-fit 避免圖片拉伸

當然,限制高寬也會出現問題,譬如圖片被拉伸了,非常的難看:

這個時候,我們可以藉助 object-fit,它能夠指定可替換元素的內容(也就是圖片)該如何適應它的父容器的高寬。

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

利用 object-fit: cover,使圖片內容在保持其寬高比的同時填充元素的整個內容框。

object-fit 的取值有 fillnonecontaincover,與 background-size 類似,可以類比記憶。

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

object-fit 還有一個配套屬性 object-position,它可以控制圖片在其內容框中的位置。(類似於 background-position),預設是 object-position: 50% 50%,如果你不希望圖片居中展示,可以使用它去改變圖片實際展示的 position。

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

像是這樣,object-position: 100% 50% 指明從底部開始展示圖片。這裡有一個很好的 Demo 可以幫助你理解 object-position

CodePen Demo -- Object position

使用 image-rendering 設定圖片縮放演演算法

相對於上面幾個新特性,image-rendering 會更為冷門。

很多時候,我們設定一個圖片在頁面上的展示大小為 200px x 200px,但是圖片的原始尺寸可能是 800px x 800px,也可能是 50px x 50px

這個時候,我們就可以利用 image-rendering,設定圖片在縮放狀態下的展示演演算法。

image-rendering 在特定的場景下,能夠起到奇效。

來看這樣一個有意思的 DEMO,假設我們有這樣一個原圖效果,它是一個二維條碼,大小為 100px x 100px

如果我們將它放大,放到很大,明顯,這個二維條碼會失真,像是這樣:

OK,在這種放大失真的情況想,可以使用 image-rendering 改變圖片縮放演演算法,這裡我們試一下 image-rendering: pixelated

.img {
  image-rendering: pixelated;
}

效果變化,如下圖所示:

可以看到,image-rendering: pixelated 處理過的影象,竟然變得如此清晰!

CodePen Demo -- QrCode Image-rendering demo

來看看 image-rendering 的幾個取值:

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

雖然規範定義了挺多值,但是實際上,現代瀏覽器基本暫時只支援:autopixelated、以及 -webkit-optimize-contrast(Chrome 下的 smooth)。

看描述都會挺懵逼的,實際使用的時候,最好每個都試一下驗證一下效果。總結而言,image-rendering 的作用是在影象縮放時,提供不一樣的渲染方式,讓圖片的展示形態更為多樣化,或者說是儘可能的去減少圖片的失真帶來的資訊損耗

我們再看一個 DEMO,原圖如下(例子來源於 W3C 規範檔案):

實際效果:

當然,看上去 pixelated 的效果挺好,這是由於這是一張偏向於向量的圖片,細節不多,對於高精度的人物圖,就不太適用於 pixelated,容易把圖片馬賽克化。

真正規範希望的在放大後讓圖片儘可能不失真的 crisp-edges 效果,目前暫時沒有得到瀏覽器的實現。後面可以期待一下。

CodePen Demo -- Image-rendering demo

總結一下

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

  • aspect-ratio:控制容器的寬高比,避免產生布局偏移及抖動
  • object-fit:設定內容應該如何適應到其使用高度和寬度確定的框,避免圖片拉伸
  • object-position:基於 object-fit,設定圖片實際展示的 position 範圍
  • image-rendering:控制圖片在縮放狀態下的展示演演算法

合理利用它們,可以給使用者在圖片上以更好的體驗。

當然,本文是現代圖片效能優化及體驗優化指南的第三篇,後續將給大家帶來圖片在:

  • 懶載入/非同步影象解碼方案
  • 可存取性以及圖片資源的容錯及錯誤處理

上的現代解決方案,感興趣的可以提前關注。

最後

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