This chapter turns CSS backgrounds from “mysterious” into predictable.
background shorthand without guessing.background ShorthandCSS layout decides where the element’s box is1. Backgrounds are then painted into that box. They don’t affect layout; they’re just pixels behind the element’s content. Backgrounds won’t show if the box has no size.
<div> with no height, it may “work” but you won’t see it)./* 2 layers, with repeating horizontal and vertical lines */
background-image:
linear-gradient(#fff9 1px, transparent 1px),
linear-gradient(90deg, #fff9 1px, transparent 1px);
background-size:
18px 18px,
18px 18px;
background-color: #97acff;
Treat linear-gradient(), radial-gradient(), and conic-gradient() as generated images.
That one idea explains why gradients behave like other background images:
background-image can contain multiple comma-separated images.background-color sits under all image layers.This is the rule most people get backwards:
background-image (or the background shorthand) is the top-most.background-color is painted under all background image layers.Try this tiny proof, the red gradient sits on top of the blue one where they overlap:
background-image:
linear-gradient(135deg, rgb(255 0 0 / 0.9), rgb(255 0 0 / 0)),
linear-gradient(135deg, rgb(0 128 255 / 0.9), rgb(0 128 255 / 0));
background-color: #111827;
When you specify multiple background layers, many related properties become lists too. Each comma-separated value maps to the layer with the same index:
background-image: url(a.png), url(b.png), url(c.png);
background-position: left top, center, right bottom;
“My background is offset / clipped / scrolling weirdly” usually comes down to which box you’re painting into.
You’ll learn the exact controls in Boxes and Scrolling. For now, remember: “positioning” and “painting” are different concepts.
When something looks wrong, don’t guess. Do this instead:
This habit scales from “one gradient” to “twelve layered recipes”.
background-color sits under all background images.background Shorthandbackground is actually shorthand forThe background shorthand can set many sub-properties at once, including:
background-colorbackground-imagebackground-positionbackground-sizebackground-repeatbackground-attachmentbackground-originbackground-clipThink of one layer as:
url(...) or a gradient function)/)The browser is flexible about token order, except for the position / size pair: the / always belongs to background-size, and it must come after the position.
compact toggle that reveals background’s default values—an excellent debugging aid.Expected output: a card with the favicon centered and not tiled.
background: url("/favicon.svg") center / 96px 96px no-repeat var(--ui-color-primary-100);
background-color property can be included in the final layer of the shorthand notation, without needing a separate layer. This demo uses a color variable./ is not a layer separatorCommas separate layers. The / only separates position from size inside one layer:
/* position / size */
background: center / cover;
When you have multiple layers:
background-color can appear once (commonly at the end). It’s painted under all image layers.background:
radial-gradient(circle at 30% 30%, rgb(255 255 255 / 0.35), transparent 55%),
linear-gradient(rgb(255 255 255 / 0.06) 1px, transparent 1px) 0 0 / 18px 18px,
linear-gradient(90deg, rgb(255 255 255 / 0.06) 1px, transparent 1px) 0 0 / 18px 18px,
#0b1020;
background-blend-mode is not part of the shorthandBlending is a separate property. For multi-layer designs you often need at least two declarations (see Blending and Compositing):
background:
url("/noise.png") 0 0 / 128px 128px repeat,
linear-gradient(135deg, #7c3aed, #06b6d4);
background-blend-mode: overlay, normal;
Common examples:
filter / backdrop-filter (post-processing)mix-blend-mode (element blending)mask-* (masking)Each comma introduces a new background layer.
Look for url(...) / image-set(...) / linear-gradient(...) / etc.
Scan for: position → optional / size → repeat → attachment → origin / clip.
If you’re unsure, rewrite that one layer as longhand temporarily. Correct > clever.
Here’s a multi-layer shorthand and its equivalent longhands.
background:
url("/favicon.svg") 24px 24px / 72px 72px no-repeat,
radial-gradient(circle at 30% 30%, rgb(255 255 255 / 0.35), transparent 55%),
#0b1020;
Equivalent longhands:
background-image:
url("/favicon.svg"),
radial-gradient(circle at 30% 30%, rgb(255 255 255 / 0.35), transparent 55%);
background-position:
24px 24px,
30% 30%;
background-size:
72px 72px,
auto;
background-repeat:
no-repeat,
repeat;
background-color: #0b1020;
If you have 3 images, you usually want 3 values for position/size/repeat too. Otherwise you’re relying on defaults or repeating behavior, which makes later edits error-prone.
center / cover/ belongs to background-size (not a separator between layers).This is common when you mix shorthand and longhand:
/* Later you add this… */
background: url("/a.png") center no-repeat;
/* …and you unknowingly reset background-size / clip / origin, etc. */
When in doubt, keep related background styles together, or use longhands. If something changes unexpectedly, compare the computed styles in your browser DevTools to spot what differs.
position / size is the special pair.You’ll learn
background-position.background-size (including cover/contain).background-repeat (including space and round).background-positionbackground-position answers: where should the image be anchored inside the box.
You can express positions using:
left, center, right, top, bottom20px 10px25% 60%/* center both axes */
background-position: center;
/* keyword pair */
background-position: right top;
/* x then y */
background-position: 100px 50px;
/* percentage x then percentage y */
background-position: 25% 60%;
/* Keyword + offset */
background-position: right 16px bottom 16px;
This is one of the most useful forms in real UI work:
background-position: right 16px bottom 16px;
Percentages are relative to the background positioning area, but the image size matters too. In practice:
0% 0% aligns the image to the top-left.50% 50% centers the image.100% 100% aligns it to the bottom-right.If the image is larger than the box, percentages still work — you’re choosing which part is visible.
background-sizebackground-size answers: how big is the image when painted.
Common values:
auto (default): use the image’s intrinsic size (or the gradient’s default sizing rules)<length> / <percentage>: explicit sizes like 80px 80px or 100% 100%contain: fit the whole image inside the box (may leave empty space)cover: fill the box completely (may crop)/* one value: width is 120px, height becomes auto */
background-size: 120px;
/* two values: width and height */
background-size: 120px 80px;
contain vs cover (what to expect)contain: always shows the whole image; might leave empty space.cover: never leaves empty space; might crop parts of the image.position / size pairing (shorthand rule)In shorthand, position / size is written like this:
background: url("/favicon.svg") center / 96px 96px no-repeat;
background-repeatbackground-repeat answers: should the image be tiled when it’s smaller than the box.
background-repeat: repeat; /* default */
background-repeat: no-repeat;
background-repeat: repeat-x;
background-repeat: repeat-y;
space and round (pattern designer modes)space keeps tile size and adds spacing so tiles fit without clipping.round adjusts tile size so an integer number of tiles fit (can subtly distort).background-repeat: space;
background-repeat: round;
background-size often matters more than repeatFor patterns (dots, grids, stripes), you often control the “tile size” with background-size. In the demonstration below, the first two layers are 50px, 50px, and combined with the default background-repeat: repeat, they form a repeating pattern:
background:
linear-gradient(to left top,
#fff 0% 20%, #ffffffe6 0 42%, #fff0 0 58%, #ffffffe6 0 80%, #fff 0 80%
)
0% 0% / 50px 50px,
linear-gradient(to left bottom,
#fff 0% 20%, #ffffffe6 0 42%, #fff0 0 58%, #ffffffe6 0 80%, #fff 0 80%
)
0% 0% / 50px 50px,
radial-gradient(circle at 100% 100%,
#ffe6a7 0%, #ffd899 20%, #ffacac 40%, #fd99ff 60%, #9edfff 80% 100%, #ebebebd1 100%
);
0 (without units) represents repeating the previous position. This is commonly used to create sharp edges.If you have multiple layers, you can control them independently:
background-image: url(a.png), url(b.png);
background-position: left top, right bottom;
background-size: 80px 80px, cover;
background-repeat: no-repeat, no-repeat;
Use the controls to see how one layer moves and scales inside the box.
120px 80px, contain, cover. /* initial value */
background-image: url("/favicon.svg");
background-position: center;
background-size: 96px 96px;
background-repeat: no-repeat;
background-color: var(--ui-color-primary-100);
position / size is the only strict ordering you must remember.This section includes:
background-origin) and painting (background-clip).background-attachment really does (and when to avoid it).Before touching origin/clip, build a box where the layers are obvious:
background-origin: Where positioning startsbackground-origin controls the background positioning area: where background-position is measured from.
Values:
padding-box (default)border-boxcontent-boxThe same background-position can land in a different place depending on which box is used as the origin.
background-clip: Where painting stopsbackground-clip controls the background painting area: where the background is allowed to paint.
Values:
border-box (default)padding-boxcontent-boxUse the demo below and switch the origin to border-box and see what the difference is:
background-image:
url("/favicon.svg"),
linear-gradient(rgb(255 255 255 / 0.25) 1px, transparent 1px),
linear-gradient(90deg, rgb(255 255 255 / 0.25) 1px, transparent 1px),
repeating-linear-gradient(to left top,#292524 0 5%,#78716c 0 10%,#57534e 0 15%,#44403c 0 20%);
background-size: 64px 64px, 16px 16px, 16px 16px, auto;
background-repeat: no-repeat, repeat, repeat, repeat;
background-position: left top, 0 0, 0 0, 0 0;
background-origin: padding-box; /* try: border-box / content-box */
background-clip: border-box; /* try: padding-box / content-box */
background-color: #0b1020;
Like other background properties, background-origin and background-clip can be a comma-separated list that matches layers.
border:16px solid transparent;
padding: 24px;
background:
linear-gradient(var(--ui-color-primary-400), var(--ui-color-primary-400)) content-box,
linear-gradient(var(--ui-color-primary-300), var(--ui-color-primary-300)) padding-box,
linear-gradient(#7c3aed, #06b6d4) border-box;
background-attachmentbackground-attachment controls whether the background is attached to:
scroll, default)local)fixed)fixed can be expensive and behaves differently on some mobile browsers. Use it deliberately.min-height: 60vh;
background-image:
linear-gradient(rgb(0 0 0 / 0.35), rgb(0 0 0 / 0.35)),
url("/photos/hero.jpg");
background-size: cover;
background-position: center;
background-attachment: fixed;
Prefer reading Dan Hollick’s article2 to learn about blend modes first.
background-blend-modebackground-blend-mode blends each background layer with the layer(s) below it (and ultimately with background-color).
It’s great for:
mix-blend-modemix-blend-mode blends an element’s pixels with whatever is behind it in the page’s stacking context.
Use it when you want:
Important interactions:
position, transform, filter) can change what gets blended.isolation: isolate can stop blending from affecting outside ancestors.mix-blend-mode: multiply;
isolation: isolate;
When a blend looks wrong:
background-blend-mode list aligns with your layers./* If you have 3 layers, you usually want 3 blend-mode values */
background-image: url(a.png), url(b.png), linear-gradient(...);
background-blend-mode: overlay, multiply, normal;
If both layers are low-contrast or nearly flat, many blend modes will look like “nothing happened”. Temporarily increase contrast while debugging.
background-blend-mode blends layers within an element.mix-blend-mode blends an element with the backdrop.position / size rule, and shorthand stops being scary.origin and clip decide where things start and where they’re allowed to paint.