第一次写背景,我们通常只会用它给盒子铺一层颜色。等到页面里出现纹理、装饰图、渐变遮罩,代码就容易变成一串反复试出来的参数。其实背景有一套明确的绘制规则:画在哪个区域、从哪里定位、怎样平铺和缩放、多个图层如何叠放,都能逐项确定。
我们从盒模型开始,把 background-color、background-clip、background-image、background-position、background-origin、background-repeat、background-attachment 和 background-size 逐一拆开。后面再把它们组合成多重背景与 background 简写,并补充常与背景一起使用的 box-shadow。遇到容易混淆的规则时,你可以直接在实验里改参数,看浏览器怎样处理。
背景不占布局空间,也不会改变元素尺寸。它画在边框和内容的下方,所以边框与内容能够盖住背景。阴影同样不参与盒模型:盒子看起来变大了,布局尺寸并没有跟着变。
普通元素从外到内分为边框区、内边距区和内容区。默认情况下,背景颜色和背景图片都能画到边框外沿,然后由边框覆盖在上面。容易混淆的是,背景图默认从内边距盒开始计算位置。也就是说,背景的绘制边界与定位基准,默认并不是同一个盒子。

分析一段背景代码时,我们可以先问两个问题:
background-clip 决定。background-origin 决定。子元素没有设置背景时,我们仍能看见祖先的背景,但这不是继承。子元素的背景默认透明,祖先已经画好的内容只是透了出来。如果背景图片真的继承,子元素会以自己的盒子为坐标重新画一遍,页面里反而会出现许多重复的图片碎片。
background-color 可以使用任何合法的颜色值。它的初始值是 transparent,适用于所有元素,不会继承,也可以参与过渡动画。
:root {
color: #172033;
background-color: #f7f4ec;
}
.notice {
padding: 1rem 1.25rem;
color: #17324d;
background-color: rgb(221 244 255 / 0.9);
}内边距在背景的默认绘制范围内,因此增加 padding 后,底色会跟着包住内容。如果第三方样式给透明 PNG、WebP 或 SVG 强加了白底,可以显式写下 background-color: transparent 把它覆盖掉。
设置文字颜色时,最好同时确认它下面的底色。普通文本的对比度至少应达到 4.5:1,大字号文本至少达到 3:1。如果只写 color,一旦背景图加载失败、半透明图层改变了合成颜色,或者用户样式介入,文字就可能难以辨认。
半透明底色最后呈现什么颜色,还取决于它下面的图层。检查对比度时,要看合成后的结果,不能只检查 rgb(... / 0.6) 这一层。
background-clip 回答的是“背景最多画到哪里”。它可用的值如下:
.card {
padding: 24px;
border: 12px dashed rgb(29 78 216 / 0.45);
background: #fef3c7;
background-clip: padding-box;
}
.painted-title {
color: transparent;
background: linear-gradient(90deg,
浏览器确定绘制区域后,还会按照圆角继续裁剪。你可以把 background-clip 看成最后落下的一把剪刀:它会隐藏越界部分,但不会改变图片的位置、大小或平铺起点。根元素的背景有特殊的画布传播规则,测试普通盒子的裁剪效果时,别用根元素来代替。
切换两个选项,观察虚线边框下哪些区域仍有底色,再看红色圆点相对哪个盒子定位。这样能直观看出 clip 与 origin 各自控制什么。
background-image 的初始值是 none。它可以接收 URL 图片、渐变等 CSS 图像,也能用逗号写成图像列表。这里要先分清图片的用途:承载信息的插图仍应使用带替代文本的 <img>;背景图更适合装饰、纹理,以及删掉后不影响内容理解的视觉层。
.hero {
background-color: #0f172a; /* 网络失败时的回退 */
background-image:
linear-gradient(rgb(15 23 42 / 0.2), rgb(15 23 42 / 0.82)),
url('/images/coast.webp');
color: white;
}URL 的相对路径以 CSS 文件所在位置为基准,不是以 HTML 文件为基准。如果图片加载失败,这一层会按 none 处理,其他图层和底色照常绘制。实际项目里还要留意资源体积。把一张大图下载下来,再缩成很小的装饰,只会白白消耗流量。
背景默认不继承,也正好避免了每个后代都从自己的盒子里重画同一张图。如果一组元素需要共享纹理,可以把背景放到它们共同的祖先上;确实需要各画一份时,再用明确的选择器逐项声明。
background-position 的默认值是 0% 0%。写两个值时,通常先写水平方向,再写垂直方向;只写一个值,另一个轴默认为 center。关键词包括 left、center、right、top 和 bottom。为了让人一眼看懂,建议把水平方向的词放在前面。
.badge {
background-position: right 16px bottom 12px;
}如果要从右边或底边向内留出一段距离,四值语法最直观,不必自己换算负值。普通长度值从定位区域左上角量起,也可以写成负数,把图片推到区域外面。
真正容易算错的是百分比。它并不是简单取容器宽度的百分比,而是让图片自身的某个百分比点和定位区域的同一百分比点对齐。换算公式如下:
实际偏移 =(定位区域尺寸 - 背景图片尺寸)× 百分比所以,0% 对应左对齐,50% 对应居中,100% 对应右对齐。如果图片比定位区域还大,公式里的可移动距离会变成负数,最终偏移自然也是负的。

background-origin 决定背景图以哪个盒子为定位区域,初始值是 padding-box:
.example {
border: 12px dashed #334155;
padding: 32px;
background-image: url('/images/dot.svg');
background-repeat: no-repeat;
background-position: 0 0;
background-origin: content-box;
background-clip: padding-box;
}选择 border-box,坐标系会从边框外沿开始,图片的一部分可能被边框盖住;padding-box 从内边距外沿开始;content-box 则从内容区边缘开始。origin 和 clip 不必取同一个值。浏览器先按照 origin 定位,再用 clip 裁剪。如果定位区域比绘制区域大,图片边缘可能被切掉;如果绘制区域更大,定位点外侧仍可能看到平铺出来的内容。
background-repeat 可以分别设置两个轴。写两个值时,第一个控制横轴,第二个控制纵轴:

平铺从最初定位的那一块图片开始,再向允许的方向延伸。因此,只要改变 background-position,整套纹理的起点也会移动。使用 space 时,如果某个轴连两张图都放不下,这个轴上的位置仍由 background-position 决定;能够放下多张时,首尾图通常贴边,剩余空间分配在中间。round 会缩放图片。如果只在一个轴上使用它,而另一轴尺寸是 auto,宽高比还可能让另一轴的尺寸跟着变化。
.pattern {
background-image: url('/images/leaf.svg');
background-repeat: space round;
background-position: center;
}要判断背景滚动时跟着谁,可以看 background-attachment 的三种模式:
scroll:默认值。背景随元素所在页面一起移动,但不会因为元素自己的内容滚动而跟着内容移动。local:背景绑定元素的滚动内容;滚动元素内部时,背景也随内容移动。fixed:背景相对视口固定,定位区域也按视口理解,再由元素的背景绘制区域裁剪显示。.notes {
overflow: auto;
background: url('/images/grid.svg') 0 0 / 24px 24px local;
}fixed 经常用来做视差效果,不过移动端浏览器可能因为性能或视口策略而采用不同的实现。关键信息不要依赖这种视觉效果,大面积固定背景也可能带来较高的重绘成本。
background-size 可以写一个或两个尺寸。只写一个值时,它表示宽度,高度取 auto;写两个值时,依次表示宽和高。长度与百分比可以混用,其中百分比相对于 background-origin 定义的定位区域计算。
.logo-watermark { background-size: 160px auto; }
.stretched { background-size: 100% 100%; }
.hero-cover { background-size: cover; }
.poster-preview { background-size: contain; }当一个轴是 auto,并且图片有固有宽高比时,浏览器通常会保持比例,算出另一个轴。两个轴都指定明确尺寸,图片就可能被拉伸。对于没有固有尺寸或比例的 CSS 图像,还要结合定位区域和图像自己的规则来计算。
cover 会在保持比例的前提下,把图片放大到刚好盖住整个定位区域,代价是部分内容可能被裁掉。contain 则把图片缩放到完整放入区域,盒子里可能留下空白。它们只控制尺寸,不会顺手关闭平铺,所以通常还要配上 no-repeat。
多个背景用逗号分层。列表里的第一张图片在最上面,后面的依次向下叠放,background-color 始终位于所有图片层下面。

.poster {
background-image:
url('/images/sparkle.svg'),
linear-gradient(rgb(15 23 42 / 0.1), rgb(15 23 42 / 0.8)),
url('/images/mountain.webp');
background-position: right 24px top 20px, center, center;
相关的长属性也都是列表,并且按层匹配。如果某个属性的值比图片层少,浏览器会循环使用这组值;如果值比图片层多,多出来的部分不会创建新图层。遇到“背景明明写了却看不见”,先检查上层图片。只要上层不透明并且铺满区域,下层就会被完全挡住。
background 能在一条声明里写下颜色、图像、定位、尺寸、重复、附着、origin 和 clip。多数值的顺序比较灵活,不过下面三条规则不能省略:
/ 分隔:center / cover。.hero {
background:
url('/images/star.svg') right 24px top 20px / 72px no-repeat,
linear-gradient(#0001, #0009) center / cover no-repeat,
#172033 url('/images/sea.webp') center / cover no-repeat;
}
.chip
简写会重置所有没有写出的背景子属性。比如先声明 background-size: cover,后面再写 background: url(...),原来的尺寸就会回到 auto。实际写代码时,可以把简写当成一条完整声明;如果还有细节需要调整,就先写简写,再用长属性覆盖。
多张背景不一定只能互相覆盖,也可以用 background-blend-mode 逐层混合。它的列表与 background-image 对齐:第一种模式处理第一张背景与下方内容的合成,后面的模式依次对应其他图层。常见值有 multiply(压暗,适合叠加纹理)、screen(提亮)、overlay(增强明暗对比)和 normal(普通覆盖)。
.texture-card {
background-image:
url('/images/paper-grain.png'),
linear-gradient(135deg, #f97316, #2563eb);
background-size: 240px, cover;
background-blend-mode: multiply, normal;
background-color: #f8fafc;
}混合结果取决于参与图层的实际颜色,换一张底图,效果可能就会明显不同。文字不属于背景图层,因此不会被 background-blend-mode 直接混合。要让整个元素与它后面的外部内容混合,应使用 mix-blend-mode。同时准备一个不依赖混合也能保证文字可读的底色,并在不同屏幕上检查最终对比度。
box-shadow 的基本顺序是水平偏移、垂直偏移、模糊半径、扩展半径和颜色,inset 可以写在开头或结尾。前两个长度必须提供;模糊半径不能是负数,扩展半径则可以。
.card {
box-shadow:
0 18px 40px -20px rgb(15 23 42 / 0.45),
inset 0 0 0 1px rgb(255 255 255 / 0.7);
}外阴影沿着边框盒的轮廓生成,靠内的部分会被边框和背景盖住;内阴影则从盒子内部边缘向里绘制。多个阴影同样用逗号分隔,第一项位于最上层。阴影不会把布局撑开,因此要为它留出视觉空间,也要留意相邻元素和 overflow: hidden 是否会把它裁掉。
真正给组件写背景时,可以按下面的顺序判断。这样每一步都有明确的问题,不容易在一长串简写里反复试值。
出问题时也可以沿着这条顺序往回查。图片完全不见,先看 URL、盒子高度,以及它是否被上层挡住。位置不对,就检查 origin 和百分比算法。cover 没有效果,看看后面的简写是否把它重置了。多背景层级混乱时,核对逗号列表的顺序。文字难读,则要检查合成后的对比度,而不是只看某一个颜色值。
最后,我们把这些属性串成一条检查路径:color/image 决定画什么,origin/position 决定从哪里放,size/repeat/attachment 决定怎样铺,clip 决定哪些部分最终可见。多背景列表负责图层顺序,简写只是把这些规则压到同一条声明里。box-shadow 能增加盒子的视觉层次,但仍不参与布局。
写完之后,别只在当前尺寸下看一眼。可以让图片加载失败一次,改变容器宽高,再测试滚动和用户配色,确认文字仍然清楚、图层没有错位。只要先分清绘制区域、定位区域和图层顺序,大多数背景问题都能顺着规则找到原因。