写了这么多年CSS,我发现有个现象很有意思:有些我们每天都在用的属性,我们以为自己很熟,但其实可能只用了它10%的功能。background-image
就是最典型的一个。
大部分时候,我们对它的使用场景,可能就是background-image: url(...)
,贴个图,完事儿。简单直接,也没什么问题。
但最近在带团队做性能优化,以及处理一些比较复杂的UI需求时,我重新发掘了一下。我发现,它结合一些现代CSS的特性,能玩出很多花样,而且对性能的帮助是实实在在的。
今天就想分享几个我这几年压箱底的、关于background-image
的技巧和思考。
作为组长,我先关心性能
一个网站的体验,加载性能是地基。地基不稳,上面的交互再华丽也没用。而图片,往往是性能问题的大头。
别再让用普通屏的用户,下载2倍图了
我们团队以前有个不好的习惯,设计师给什么图,我们就直接用什么图,经常一张@2x
的高清图用到底。这对性能是灾难,尤其是在移动端。后来我强制大家在用背景图时,必须考虑响应式。
很多人第一反应是用媒体查询,但那样写起来很啰嗦。其实CSS自己就提供了更好的方案:image-set()
。
CSS
.hero-banner {
/* 写法一:根据屏幕像素密度(1x, 2x)来选择
这是最基础的用法,能保证高清屏的用户看到高清图,普通屏的用户下载小图。
*/
background-image: image-set(
url("hero-small.jpg") 1x,
url("hero-large.jpg") 2x
);
/* 写法二(我更推荐的):结合新一代图片格式
浏览器会从左到右检查,加载它支持的第一个格式。
这样一来,支持AVIF的浏览器就能享受到极致的压缩率,不支持的也能优雅降级。
*/
background-image: image-set(
url("hero.avif") type("image/avif"),
url("hero.webp") type("image/webp"),
url("hero.jpg") type("image/jpeg")
);
}
image-set()
应该成为我们团队CSS代码规范的一部分。它是一种声明式的、把决策权交给浏览器的现代做法,比我们自己写一堆媒体查询要优雅得多。
能用"渐变"画的,就别发HTTP请求
我一直很着迷于"零依赖"的实现。能用CSS自己画出来的东西,就绝不麻烦网络。
比如,我们需要一个半透明的遮罩,或者一些简单的条纹背景。很多同学下意识地就想让设计师切图。但其实,渐变函数就能搞定,而且效果更好。

CSS
/* 一个简单的从上到下半透明黑色遮罩 */
.overlay {
background-image: linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5));
}
/* 一个更复杂的斜条纹图案 */
.striped-pattern {
background-image: linear-gradient(
45deg,
#f0f0f0 25%, transparent 25%,
transparent 50%, #f0f0f0 50%,
#f0f0f0 75%, transparent 75%,
transparent 100%
);
background-size: 40px 40px;
}
这不只是少了一次HTTP请求那么简单。CSS渐变是矢量的,无限缩放不失真,而且它的颜色、大小,都可以用CSS变量来动态控制,在做主题换肤之类的功能时,比图片方便得多。我鼓励我们组的同学,在做这种简单背景时,优先考虑CSS渐变。
再聊聊几个我最近在玩的"花活儿"
除了性能,background-image
也能帮我们用更少的HTML,实现更丰富的视觉效果。
用多重背景,像P图一样"堆图层"
这个技巧我特别喜欢,因为它让我想起了在Figma或Photoshop里玩图层。能用一个div
解决的问题,就绝不用两个。
background-image
以及它的一系列相关属性(position
, repeat
, size
等),都支持用逗号分隔,来定义多个背景层。
CSS
.card {
background-image:
url('icon.svg'), /* 最顶层:一个居中的小图标 */
linear-gradient(to top, rgba(0,0,0,0.6), transparent), /* 中间层:一个底部半透明渐变 */
url('texture.jpg'); /* 最底层:一个平铺的纹理 */
/* 每一层的属性,也用逗号分隔,一一对应 */
background-repeat:
no-repeat,
no-repeat,
repeat;
background-position:
center,
bottom,
top left;
background-size:
60px, /* icon的大小 */
100% 50%, /* 渐变的高度占50% */
auto; /* 纹理用原始大小 */
}
这种写法,极大地保持了HTML结构的语义化和整洁。我们不需要为了视觉效果,去添加无意义的<span>
或者<div>
包装层。所有的视觉逻辑,都内聚在了CSS里。
用background-clip: text
,做个"高级感"的渐变文字
有时候,产品和设计会提一些想要"眼前一亮"的效果,渐变文字就是最常见的一种。很多新同学可能会觉得这得用SVG或者Canvas,其实CSS自己就能搞定。

CSS
.gradient-title {
position: relative;
font-weight: bold;
text-transform: uppercase;
/* 1. 先准备一个渐变背景 */
background-image: linear-gradient(90deg, #FF3684, #FF8F1D, #FF3684, #FF8F1D);
background-size: 300%;
/* 2. 关键!把背景裁剪成文字的形状 */
-webkit-background-clip: text; /* 兼容一下老浏览器 */
background-clip: text;
/* 3. 把文字颜色设成透明,好让下面的背景"透"上来 */
color: transparent;
animation: gradientMove 2s infinite linear;
}
这是一个典型的"知道就会,不知道就抓瞎"的技巧。我经常用这个例子告诉我们组的新人,多去MDN上翻翻那些不常用的CSS属性,有时候会有意想不到的惊喜。
所以你看,background-image
远不止url()
贴个图那么简单。
作为一个带团队的人,我总跟组里的同学说,每个代码工具,你都要知道它的极限在哪。把一个background-image
这样的基础属性玩透了,比你会十个新框架的"Hello World",在某些时候更有价值。
大概就这些吧,都是我平时项目中积累的一些心得。不知道大家还有没有别的关于background-image
的骚操作?可以交流一下。