歡迎關注我的公眾號:前端偵探
聊聊圖片與背景圖片
大部分注重內容的圖片(比如商品展示、文章配圖)都推薦直接使用img
標籤,好處有很多,比如
img
支持天然懶加載,設置loading="lazy"
<img src='xxx.png' loading="lazy">
img
支持各種JS
監聽,比如加載成功、加載失敗
<img src='xxx.png' onload="" onerror="">
img
支持自定義解碼,同步還是異步
<img src='xxx.png' decoding="sync">
img
對SEO更加優化,對可訪問性更好
<img src='xxx.png' alt="頭像">
但是,除了上面這些,在視覺表現上,圖片靈活性就不如背景圖片了。
比如img
不支持重複平鋪、不支持圖片疊加等等,也不像普通標籤還可以使用偽元素。
這樣就導致很多時候,比如要在img
外面嵌套一層容器再額外處理,還是有些不便的,特別是在HTML
不方便修改的情況下。
那麼,有沒有什麼辦法,可以將img
轉換成background-image
呢? 也就是使用img
標籤,但是卻可以使用背景圖的諸多特性。
img
是一個可替換標籤,意思就是這個標籤的渲染內容是由外部決定的。
這樣就導致img
和一般標籤有些不同,比如沒有偽元素,而且資源的層級是高於一些裝飾性属性的,例如背景、內陰影等。
比如,我們給一個img
標籤添加一個背景
<img src="xxx.png" style="background:red">
效果如下
沒有看到任何紅色背景,說明圖片的層級是高於背景的。
如果我們換一個帶透明像素的圖片,就能看到背景了。
所以,下面的問題就是,如何把img
本身的圖片給隱藏起來?
當然這裡說的隱藏並不是直接隱藏整個img
標籤,比如
img {
opacity: 0; /*🙅🏻*/
}
這樣的話,整個標籤都看不見了,背景也看不見了,也就失去了轉換的意義。
那還有什麼辦法可以隱藏呢?這裡有兩種方式。
content
替換內容在之前,可以從可替換標籤入手,透過content
屬性可以改變可替換元素的內容,就像這樣
img {
content: url(xx.png);
}
我們給img
標籤一個透明的圖片內容,就可以替換img
原本的顯示了,這裡可以用1*1
像素的透明gif
img {
content: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);
}
但是,這樣設置以後,圖片完全不可見了。這樣因為,此時的img
已經被渲染成1*1
像素了。
所以在用這種方式時,必須手動指定寬高,
img {
content: url(xxx.png);
width: 300px;
height: 300px;
}
為了方便觀察,我們加上邊框。
這樣原始的img
連結已經被隱藏了。
object-position
偏移上面的方式比較硬核,還可以設置一張錯誤的圖片,讓圖片展示直接出錯,這樣還能使用偽元素。
不過,有個小缺陷是,必須要手動指定圖片寬高,可能存在一定的限制。
下面介紹另一個方式,那就是透過object-position
改變圖片的顯示位置。比如
img {
object-position: 100px;
}
效果如下。
我們只需要給個足夠大的值,圖片就完全移出標籤外了。
img {
object-position: 100vw; /**足夠大的偏移*/
}
這樣也能隱藏圖片的展示,而且也不影響img
原本尺寸。
注意,這裡不能用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…
效果如下。
背景尺寸有些不對,我們調整一下。
img {
background: image-set(attr(src)) 0 0/100%;
}
這樣就透過背景完美替換了圖片。
不過這個需要用過attr
的新特性,要求兼容性 chrome 133+
。
更常見的做法是透過自定義屬性來實現。
<img src="xxx.png" style="--bg: url(xxx.png)">
然後直接使用這個變數。
img {
background: var(--bg) 0 0/100%;
}
費了一番功夫轉換成了背景圖片,有哪些好處呢?下面舉幾個例子。
通常我們使用border
實現的邊框都是外邊框,無法直接覆蓋在圖片上,有時候需要一種半透明邊框來強化圖片的輪廓,比如下面的書封。
這時,我們可以透過內陰影來實現這樣的效果(內陰影的層級高於背景)。
img {
background: image-set(attr(src)) 0 0/100%;
border-radius: 8px;
box-shadow: inset 0 0 0 2px rgba(0,0,0,.1);
}
效果如下。
有時候書封還需要高光或者水印,這樣會更有質感一些,就像這樣。
這時,我們可以直接給圖片疊加一層高光素材就行了。
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%;
}
效果如下。
也可以疊加一層平鋪的水印。
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;
}
效果如下。
可以在不嵌套標籤的情況下實現圖片縮放效果。
img {
transition: .3s;
}
img:hover {
background-size: 120%;
}
效果如下。
以上所有 demo 可以查看:codepen.io/xboxyan/pen…
其實上面的實現都可以透過嵌套一層標籤來實現,這裡其實針對的是那種 html
結構不方便修改的情況,比如是框架自己生成的,或者在一些富文本編輯器了,嵌套一層會有更多的麻煩。
這樣一個自定義img
標籤小技巧,你學到了嗎?最後,如果覺得還不錯,對你有幫助的話,歡迎點贊、收藏、轉發 ❤❤❤