CSS 小技巧:如何将 img 转换成 background-image

欢迎关注我的公众号:前端侦探

聊聊图片与背景图片

一、img vs background-image

大部分注重内容的图片(比如商品展示、文章配图)都推荐直接使用img标签,好处有很多,比如

  1. img支持天然懒加载,设置loading="lazy"
html 复制代码
<img src='xxx.png' loading="lazy">
  1. img支持各种JS监听,比如加载成功、加载失败
html 复制代码
<img src='xxx.png' onload="" onerror="">
  1. img支持自定义解码,同步还是异步
html 复制代码
<img src='xxx.png' decoding="sync">
  1. img对SEO更加优化,对可访问性更好
html 复制代码
<img src='xxx.png' alt="头像">

但是,除了上面这些,在视觉表现上,图片灵活性就不如背景图片了。

比如img不支持重复平铺、不支持图片叠加等等,也不像普通标签还可以使用伪元素。

这样就导致很多时候,比如要在img外面嵌套一层容器再额外处理,还是有些不便的,特别是在HTML不方便修改的情况下。

那么,有没有什么办法,可以将img转换成background-image呢? 也就是使用img标签,但是却可以使用背景图的诸多特性。

二、img 的层级

img是一个可替换标签,意思就是这个标签的渲染内容是由外部决定的。

这样就导致img和一般标签有些不同,比如没有伪元素,而且资源的层级是高于一些装饰性属性的,例如背景、内阴影等

比如,我们给一个img标签添加一个背景

html 复制代码
<img src="xxx.png" style="background:red">

效果如下

没有看到任何红色背景,说明图片的层级是高于背景的。

如果我们换一个带透明像素的图片,就能看到背景了

所以,下面的问题就是,如何把img本身的图片给隐藏起来?

三、如何隐藏 img 资源?

当然这里说的隐藏并不是直接隐藏整个img标签,比如

css 复制代码
img {
  opacity: 0 /*🙅🏻‍*/
}

这样的话,整个标签都看不见了,背景也看不见了,也就失去了转换的意义。

那还有什么办法可以隐藏呢?这里有两种方式

1. 通过content替换内容

在之前,可以从可替换标签入手,通过content属性可以改变可替换元素的内容,就像这样

css 复制代码
img {
  content: url(xx.png)
}

我们给img标签一个透明的图片内容,就可以替换img原本的显示了,这里可以用1*1像素的透明gif

css 复制代码
img {
  content: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);
}

但是,这样设置以后,图片完全不可见了。这样因为,此时的img已经被渲染成1*1像素了

所以在用这种方式时,必须手动指定宽高,

css 复制代码
img {
  content: url(xxx.png);
  width: 300px;
  height: 300px;
}

为了方便观察,我们加上边框

这样原始的img链接已经被隐藏了

2. 通过object-position偏移

上面的方式比较硬核,还可以设置一张错误的图片,让图片展示直接出错,这样还能使用伪元素。

不过,有个小缺陷是,必须要手动指定图片宽高,可能存在一定的限制。

下面介绍另一个方式,那就是通过object-positon收到改变图片的显示位置。比如

css 复制代码
img {
  object-position: 100px;
}

效果如下

我们只需要给个足够大的值,图片就完全移出标签外了

css 复制代码
img {
  object-position: 100vw; /**足够大的偏移/
}

这样也能隐藏图片的展示,而且也不影响img原本尺寸

注意,这里不能用object-position: 100%来实现,和背景位置比较像,100%表示居右了,并不是向右偏移自身的100%

四、如何通过背景图片显示

再回到img标签本身,有办法直接通过src属性直接显示为背景图片吗?

html 复制代码
<img src="xxx.png">

在之前这篇文章:原子化的未来?了解一下全面进化的CSS attr函数 有提到attr的新特性。

但是,出于安全考虑,并不能直接显示背景图片

css 复制代码
img{
  background: url(attr(src));
}

其实呢,还可以用image-set来直接渲染字符串格式的资源,写法如下

css 复制代码
img {
  background: image-set(attr(src));
}

这个技巧是在张鑫旭的这篇文章中学到的:www.zhangxinxu.com/wordpress/2...

效果如下

背景尺寸有些不对,我们调整一下

css 复制代码
img {
  background: image-set(attr(src)) 0 0/100%;
}

这样就通过背景完美替换了图片

不过这个需要用过attr的新特性,要求兼容性 chrome 133+

更常见的做法是通过自定义属性来实现

html 复制代码
<img src="xxx.png" style="--bg: url(xxx.png)">

然后直接使用这个变量

css 复制代码
img {
  background: var(--bg) 0 0/100%;
}

五、转换成背景图片后的好处

费了一番功夫转换成了背景图片,有哪些好处呢?下面举几个例子

1. 图片内边框

通常我们使用border实现的边框都是外边框,无法直接覆盖在图片上,有时候需要一种半透明边框来强化图片的轮廓,比如下面的书封

这时,我们可以通过内阴影来实现这样的效果(内阴影的层级高于背景)

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

效果如下

2. 图片高光或者水印

有时候书封还需要高光或者水印,这样会更有质感一些,就像这样

这时,我们可以直接给图片叠加一层高光素材就行了

css 复制代码
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%;
}

效果如下

也可以叠加一层平铺的水印

css 复制代码
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;
}

效果如下

3. 图片缩放效果

可以在不嵌套标签的情况下实现图片缩放效果

css 复制代码
img{
  transition: .3s;
}
img:hover{
  background-size: 120%;
}

效果如下

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

六、更多一种选择

其实上面的实现都可以通过嵌套一层标签来实现,这里其实针对的是那种 html 结构不方便修改的情况,比如是框架自己生成的,或者在一些富文本编辑器了,嵌套一层会有更多的麻烦。

这样一个自定义img标签小技巧,你学到了吗?最后,如果觉得还不错,对你有帮助的话,欢迎点赞、收藏、转发 ❤❤❤

相关推荐
LinXunFeng19 分钟前
Flutter - 详情页初始锚点与优化
前端·flutter·开源
GISer_Jing23 分钟前
Vue Teleport 原理解析与React Portal、 Fragment 组件
前端·vue.js·react.js
Summer不秃43 分钟前
uniapp 手写签名组件开发全攻略
前端·javascript·vue.js·微信小程序·小程序·html
coderklaus1 小时前
Base64编码详解
前端·javascript
NobodyDJ1 小时前
Vue3 响应式大对比:ref vs reactive,到底该怎么选?
前端·vue.js·面试
xianxin_1 小时前
CSS Visibility(可见性)
前端
朱程1 小时前
写给自己的 LangChain 开发教程(二):格式化数据 & 提取 & 分类
前端·人工智能
小喷友1 小时前
第5章 高级UI与动画
前端·app·harmonyos
笃行3501 小时前
【实用部署教程】olmOCR智能PDF文本提取系统:从安装到可视化界面实现
前端
庚云1 小时前
🔒 前后端 AES 加密解密实战(Vue3 + Node.js)
前端·后端