歡迎關注我的公眾號:前端偵探

聊聊圖片與背景圖片

一、img vs background-image

大部分注重內容的圖片(比如商品展示、文章配圖)都推薦直接使用img標籤,好處有很多,比如

  1. img支持天然懶加載,設置loading="lazy"

    <img src='xxx.png' loading="lazy">
  2. img支持各種JS監聽,比如加載成功、加載失敗

    <img src='xxx.png' onload="" onerror="">
  3. img支持自定義解碼,同步還是異步

    <img src='xxx.png' decoding="sync">
  4. img對SEO更加優化,對可訪問性更好

    <img src='xxx.png' alt="頭像">

但是,除了上面這些,在視覺表現上,圖片靈活性就不如背景圖片了。

比如img不支持重複平鋪、不支持圖片疊加等等,也不像普通標籤還可以使用偽元素。

這樣就導致很多時候,比如要在img外面嵌套一層容器再額外處理,還是有些不便的,特別是在HTML不方便修改的情況下。

那麼,有沒有什麼辦法,可以將img轉換成background-image呢? 也就是使用img標籤,但是卻可以使用背景圖的諸多特性。

image

二、img 的層級

img是一個可替換標籤,意思就是這個標籤的渲染內容是由外部決定的。

這樣就導致img和一般標籤有些不同,比如沒有偽元素,而且資源的層級是高於一些裝飾性属性的,例如背景、內陰影等。

image

比如,我們給一個img標籤添加一個背景

<img src="xxx.png" style="background:red">

效果如下

image

沒有看到任何紅色背景,說明圖片的層級是高於背景的。

如果我們換一個帶透明像素的圖片,就能看到背景了。

image

所以,下面的問題就是,如何把img本身的圖片給隱藏起來?

三、如何隱藏 img 資源?

當然這裡說的隱藏並不是直接隱藏整個img標籤,比如

img {
  opacity: 0; /*🙅🏻‍*/
}

這樣的話,整個標籤都看不見了,背景也看不見了,也就失去了轉換的意義。

那還有什麼辦法可以隱藏呢?這裡有兩種方式。

1. 透過content替換內容

在之前,可以從可替換標籤入手,透過content屬性可以改變可替換元素的內容,就像這樣

img {
  content: url(xx.png);
}

我們給img標籤一個透明的圖片內容,就可以替換img原本的顯示了,這裡可以用1*1像素的透明gif

img {
  content: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);
}

但是,這樣設置以後,圖片完全不可見了。這樣因為,此時的img已經被渲染成1*1像素了。

image

所以在用這種方式時,必須手動指定寬高,

img {
  content: url(xxx.png);
  width: 300px;
  height: 300px;
}

為了方便觀察,我們加上邊框。

image

這樣原始的img連結已經被隱藏了。

2. 透過object-position偏移

上面的方式比較硬核,還可以設置一張錯誤的圖片,讓圖片展示直接出錯,這樣還能使用偽元素。

不過,有個小缺陷是,必須要手動指定圖片寬高,可能存在一定的限制。

下面介紹另一個方式,那就是透過object-position改變圖片的顯示位置。比如

img {
  object-position: 100px;
}

效果如下。

image

我們只需要給個足夠大的值,圖片就完全移出標籤外了。

img {
  object-position: 100vw; /**足夠大的偏移*/
}

這樣也能隱藏圖片的展示,而且也不影響img原本尺寸。

image

注意,這裡不能用object-position: 100%來實現,和背景位置比較像,100%表示居右了,並不是向右偏移自身的100%

四、如何透過背景圖片顯示

再回到img標籤本身,有辦法直接透過src屬性直接顯示為背景圖片嗎?

<img src="xxx.png">

在之前這篇文章:原子化的未來?了解一下全面進化的CSS attr函數 有提到attr的新特性。

但是,出於安全考量,並不能直接顯示背景圖片。

img {
  background: url(attr(src));
}

其實呢,還可以用image-set來直接渲染字串格式的資源,寫法如下。

img {
  background: image-set(attr(src));
}

這個技巧是在張鑫旭的這篇文章中學到的:www.zhangxinxu.com/wordpress/2…

效果如下。

image

背景尺寸有些不對,我們調整一下。

img {
  background: image-set(attr(src)) 0 0/100%;
}

這樣就透過背景完美替換了圖片。

image

不過這個需要用過attr的新特性,要求兼容性 chrome 133+

更常見的做法是透過自定義屬性來實現。

<img src="xxx.png" style="--bg: url(xxx.png)">

然後直接使用這個變數。

img {
  background: var(--bg) 0 0/100%;
}

五、轉換成背景圖片後的好處

費了一番功夫轉換成了背景圖片,有哪些好處呢?下面舉幾個例子。

1. 圖片內邊框

通常我們使用border實現的邊框都是外邊框,無法直接覆蓋在圖片上,有時候需要一種半透明邊框來強化圖片的輪廓,比如下面的書封。

image

這時,我們可以透過內陰影來實現這樣的效果(內陰影的層級高於背景)。

img {
  background: image-set(attr(src)) 0 0/100%;
  border-radius: 8px;
  box-shadow: inset 0 0 0 2px rgba(0,0,0,.1);
}

效果如下。

image

2. 圖片高光或者水印

有時候書封還需要高光或者水印,這樣會更有質感一些,就像這樣。

image

這時,我們可以直接給圖片疊加一層高光素材就行了。

img {
  background: url("https://imgservices-1252317822.image.myqcloud.com/coco/s03272025/e21047d7.v7q5ko.png") 0 0/100% 100%, image-set(attr(src)) 0 0/100%;
}

效果如下。

image

也可以疊加一層平鋪的水印。

img {
  --water: url("data:image/svg+xml,%3Csvg width='150' height='150' style='transform:rotate(-45deg)' xmlns='http://www.w3.org/2000/svg'%3E%3Ctext x='50%25' y='50%25' font-size='14' fill='%23a2a9b6' font-family='system-ui, sans-serif' text-anchor='middle' dominant-baseline='middle'%3E前端偵探%3C/text%3E%3C/svg%3E");
  background: var(--water) 50%/28%, image-set(attr(src)) 0 0/100%;
  box-shadow: inset 0 0 0 4px rebeccapurple;
}

效果如下。

image

3. 圖片縮放效果

可以在不嵌套標籤的情況下實現圖片縮放效果。

img {
  transition: .3s;
}
img:hover {
  background-size: 120%;
}

效果如下。

image

以上所有 demo 可以查看:codepen.io/xboxyan/pen…

六、更容易的一種選擇

其實上面的實現都可以透過嵌套一層標籤來實現,這裡其實針對的是那種 html 結構不方便修改的情況,比如是框架自己生成的,或者在一些富文本編輯器了,嵌套一層會有更多的麻煩。

這樣一個自定義img標籤小技巧,你學到了嗎?最後,如果覺得還不錯,對你有幫助的話,歡迎點贊、收藏、轉發 ❤❤❤


原文出處:https://juejin.cn/post/7541436591899050010


精選技術文章翻譯,幫助開發者持續吸收新知。

共有 0 則留言


精選技術文章翻譯,幫助開發者持續吸收新知。
🏆 本月排行榜
🥇
站長阿川
📝11   💬6   ❤️5
474
🥈
我愛JS
📝1   💬5   ❤️4
95
🥉
AppleLily
📝1   💬4   ❤️1
56
#4
💬1  
5
#5
xxuan
💬1  
3
評分標準:發文×10 + 留言×3 + 獲讚×5 + 點讚×1 + 瀏覽數÷10
本數據每小時更新一次