What CSS “background” means
In CSS, background is a family of properties that paint “behind” an element’s content. You can paint a color, an image, or even a gradient. And you can control how that paint behaves: where it sits, how it scales, whether it repeats, and more.
A key idea that’ll save you from many “why is this weird?” moments: CSS backgrounds are like wallpaper for
an element — they’re not actual DOM elements. That means you can’t select a background image with CSS selectors, and
it doesn’t affect layout like an <img> tag does.
.demo { background: #ffe08a; }
.demo { background: #c7f9cc; }
.demo { background: #a0c4ff; }
*, ::before, ::after { box-sizing: border-box; } body { font-family: ui-sans-serif, system-ui, sans-serif; } .demo { width: min(640px, 100%); padding: 24px; border: 3px solid #111; border-radius: 14px; } .demo h3 { margin: 0 0 10px; font-size: 20px; } .demo p { margin: 0; line-height: 1.4; }
Backgrounds paint behind content
Try switching snippets. The content stays put, the “paint” changes.
CSS background color
The simplest background is background-color (or the shorthand background). It fills the
element’s background painting area (by default, the area inside the border).
background-color and the background shorthand
These two are equivalent for plain colors:
background-color: #ffd6a5;background: #ffd6a5;
People often use background because it’s shorter and also lets you set images, positions, sizes, and
repeats. Just remember: the shorthand can reset other background sub-properties you previously set.
.card { background-color: #ffd6a5; }
.card { background: #bdb2ff; }
.card { background: #111; color: #fff; }
*, ::before, ::after { box-sizing: border-box; } .card { width: min(640px, 100%); padding: 18px 18px; border: 3px solid #111; border-radius: 16px; font-family: ui-sans-serif, system-ui, sans-serif; } .card h3 { margin: 0 0 8px; font-size: 20px; } .card p { margin: 0; line-height: 1.4; }
Background color
Pick a snippet. Same element, different paint.
CSS background image
A background image is set with background-image (or the background shorthand). By default,
the image repeats (tiles) in both directions. That’s because backgrounds were originally designed for patterns.
Adding a background image
Let’s use a real image and see the default behavior (repeat).
.hero { background-image: url("https://picsum.photos/300/140"); }
.hero { background-image: url("https://picsum.photos/300/140"); background-repeat: no-repeat; }
.hero { background-image: url("https://picsum.photos/300/140"); background-repeat: repeat-x; }
*, ::before, ::after { box-sizing: border-box; } .hero { width: min(720px, 100%); height: 260px; border: 3px solid #111; border-radius: 18px; overflow: hidden; font-family: ui-sans-serif, system-ui, sans-serif; padding: 16px; display: grid; align-content: start; gap: 8px; } .badge { display: inline-block; width: fit-content; padding: 6px 10px; border-radius: 999px; border: 2px solid #111; background: rgba(255, 255, 255, 0.85); font-size: 14px; } .hero h3 { margin: 0; font-size: 20px; background: rgba(255, 255, 255, 0.85); width: fit-content; padding: 6px 10px; border-radius: 10px; border: 2px solid #111; }
Background image demoWatch how it repeats by default
Where the paint goes: background-clip and background-origin
Two less-famous but very useful properties:
- background-clip decides how far the background is allowed to paint (to the border edge, padding edge, or content box).
- background-origin decides where the background positioning starts from (border box, padding box, content box).
.panel { background: url("https://picsum.photos/900/700"); background-size: cover; background-repeat: no-repeat; background-clip: border-box; }
.panel { background: url("https://picsum.photos/900/700"); background-size: cover; background-repeat: no-repeat; background-clip: padding-box; }
.panel { background: url("https://picsum.photos/900/700"); background-size: cover; background-repeat: no-repeat; background-clip: content-box; }
*, ::before, ::after { box-sizing: border-box; } .panel { width: min(720px, 100%); height: 260px; border: 10px dashed #111; padding: 18px; border-radius: 20px; font-family: ui-sans-serif, system-ui, sans-serif; display: grid; place-items: center; } .panel .label { background: rgba(255, 255, 255, 0.88); border: 2px solid #111; border-radius: 12px; padding: 10px 12px; }
Try the snippets: border-box vs padding-box vs content-box
CSS background size
background-size controls how big the background image is inside the element. The most common values are
cover and contain.
- cover fills the whole element (no empty space), but may crop the image.
- contain keeps the whole image visible, but may leave empty space.
cover vs contain vs exact sizing
.box { background-image: url("https://picsum.photos/900/600"); background-repeat: no-repeat; background-size: cover; }
.box { background-image: url("https://picsum.photos/900/600"); background-repeat: no-repeat; background-size: contain; }
.box { background-image: url("https://picsum.photos/900/600"); background-repeat: no-repeat; background-size: 220px 140px; }
*, ::before, ::after { box-sizing: border-box; } .box { width: min(720px, 100%); height: 260px; border: 3px solid #111; border-radius: 18px; font-family: ui-sans-serif, system-ui, sans-serif; padding: 16px; display: grid; align-content: start; gap: 8px; } .note { background: rgba(255, 255, 255, 0.88); border: 2px solid #111; border-radius: 12px; padding: 10px 12px; width: fit-content; }
Try: cover, contain, fixed px size
Interactive background-size with a slider
When you set a single length value (like 120%), you’re effectively scaling the background image. Let’s
make that interactive.
.zoom { background-image: url("https://picsum.photos/900/650"); background-repeat: no-repeat; background-position: center; background-size: 110%; }
*, ::before, ::after { box-sizing: border-box; } .zoom { width: min(720px, 100%); height: 280px; border: 3px solid #111; border-radius: 18px; overflow: hidden; font-family: ui-sans-serif, system-ui, sans-serif; display: grid; place-items: end start; padding: 14px; } .zoom .label { background: rgba(255, 255, 255, 0.9); border: 2px solid #111; border-radius: 12px; padding: 8px 10px; }
Slide to “zoom” the background
CSS background position
background-position decides where the background image sits inside the element. It can use keywords
(left, center, right, top, bottom), percentages, or
lengths like px.
Keywords, percentages, and lengths
.stage { background-image: url("https://picsum.photos/950/650"); background-repeat: no-repeat; background-size: cover; background-position: center; }
.stage { background-image: url("https://picsum.photos/950/650"); background-repeat: no-repeat; background-size: cover; background-position: left top; }
.stage { background-image: url("https://picsum.photos/950/650"); background-repeat: no-repeat; background-size: cover; background-position: 80% 30%; }
*, ::before, ::after { box-sizing: border-box; } .stage { width: min(720px, 100%); height: 280px; border: 3px solid #111; border-radius: 18px; overflow: hidden; font-family: ui-sans-serif, system-ui, sans-serif; padding: 14px; display: grid; place-items: start; } .tag { background: rgba(255, 255, 255, 0.9); border: 2px solid #111; border-radius: 999px; padding: 6px 10px; font-size: 14px; }
Move the “camera” with background-position
CSS Background position with center, top, bottom, left, right values
Click on the different named values that can have CSS Background position
.photo { background-image: url("https://picsum.photos/950/650"); background-repeat: no-repeat; background-size: cover; background-position: center; }
*, ::before, ::after { box-sizing: border-box; } .photo { width: min(720px, 100%); height: 280px; border: 3px solid #111; border-radius: 18px; overflow: hidden; }
Left and Right look the same, because the background is set to background-size: cover; and here the width is the limiting factor.
CSS background image fit
People often say “fit” when they really mean how an image fills a box. For background images, that
“fit” is controlled by background-size:
- cover behaves like “fill the box, crop if needed”
- contain behaves like “show the whole thing, letterbox if needed”
Background “fit” vs <img> object-fit
An <img> element uses object-fit. A background image uses
background-size. They can look similar, but they apply to different things.
.wrap { display: grid; gap: 14px; }
.bg {
height: 220px;
border-radius: 16px;
background-image: url("https://picsum.photos/900/650");
background-repeat: no-repeat;
background-size: cover;
background-position: center;
}
.img img {
width: 100%;
height: 220px;
display: block;
object-fit: cover;
border-radius: 16px;
}
.wrap { display: grid; gap: 14px; } .bg { height: 220px; border-radius: 16px; background-image: url("https://picsum.photos/900/650"); background-repeat: no-repeat; background-size: contain; background-position: center; background-color: #f2f2f2; } .img img { width: 100%; height: 220px; display: block; object-fit: contain; border-radius: 16px; background: #f2f2f2; }
*, ::before, ::after { box-sizing: border-box; } .wrap { width: min(720px, 100%); font-family: ui-sans-serif, system-ui, sans-serif; } .card { border: 3px solid #111; border-radius: 18px; padding: 14px; } .title { margin: 0 0 10px; font-size: 16px; } .bg { border: 2px solid #111; } .img img { border: 2px solid #111; }
Background image (uses background-size)
<img> (uses object-fit)
![]()
CSS background gradient
Gradients are “generated images” in CSS. That’s why they’re used with background-image (or the
background shorthand).
Linear and radial gradients
.tile { background-image: linear-gradient(90deg, #ffadad, #ffd6a5, #fdffb6); }
.tile { background-image: linear-gradient(135deg, #a0c4ff, #bdb2ff, #ffc6ff); }
.tile { background-image: radial-gradient(circle at 30% 30%, #caffbf, #9bf6ff, #a0c4ff); }
*, ::before, ::after { box-sizing: border-box; } .tile { width: min(720px, 100%); height: 260px; border: 3px solid #111; border-radius: 18px; font-family: ui-sans-serif, system-ui, sans-serif; display: grid; place-items: center; } .tile .text { background: rgba(255, 255, 255, 0.88); border: 2px solid #111; border-radius: 12px; padding: 10px 12px; }
Gradients are backgrounds too
Learn more about gradients in the CSS Gradient Interactive Tutorial.
Layering multiple backgrounds
You can stack multiple backgrounds by separating them with commas. The first one is painted on top of the next one (like layers).
.banner { background-image: linear-gradient(90deg, rgba(0, 0, 0, 0.55), rgba(0, 0, 0, 0)), url("https://picsum.photos/980/520"); background-size: cover; background-position: center; background-repeat: no-repeat; }
.banner { background-image: radial-gradient(circle at 30% 30%, rgba(255, 255, 255, 0.75), rgba(255, 255, 255, 0)), url("https://picsum.photos/980/520"); background-size: cover; background-position: center; background-repeat: no-repeat; }
*, ::before, ::after { box-sizing: border-box; } .banner { width: min(720px, 100%); height: 260px; border: 3px solid #111; border-radius: 18px; overflow: hidden; font-family: ui-sans-serif, system-ui, sans-serif; display: grid; place-items: end start; padding: 16px; } .banner .headline { margin: 0; color: #fff; font-size: 22px; letter-spacing: 0.2px; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.35); }
CSS background opacity and background image opacity
There’s no background-opacity property in CSS. If you do opacity: 0.5; on the element,
you’ll fade everything (background and text and children). That’s usually not
what you want.
Here are three correct patterns:
- Use an alpha color for background-color (like
rgba()). - Layer a semi-transparent gradient over the image.
- Use a pseudo-element (
::before) for the background and fade that layer only.
Pattern 1: Alpha background-color (only affects the color)
.card { background: rgba(255, 255, 255, 0.65); }
.card { background: rgba(0, 0, 0, 0.55); color: #fff; }
*, ::before, ::after { box-sizing: border-box; } .shell { width: min(720px, 100%); border-radius: 18px; border: 3px solid #111; overflow: hidden; background-image: url("https://picsum.photos/980/520"); background-size: cover; background-position: center; background-repeat: no-repeat; padding: 18px; font-family: ui-sans-serif, system-ui, sans-serif; } .card { border: 2px solid #111; border-radius: 16px; padding: 16px; } .card h3 { margin: 0 0 8px; font-size: 20px; } .card p { margin: 0; line-height: 1.4; }
Only the background color is transparent
The text stays fully opaque.
Pattern 2: Overlay gradient on top of the image
This is a super common trick to “make text readable on a photo”.
.hero { background-image: linear-gradient(90deg, rgba(0, 0, 0, 0.65), rgba(0, 0, 0, 0)), url("https://picsum.photos/980/520"); }
.hero { background-image: linear-gradient(180deg, rgba(255, 255, 255, 0.75), rgba(255, 255, 255, 0)), url("https://picsum.photos/980/520"); }
*, ::before, ::after { box-sizing: border-box; } .hero { width: min(720px, 100%); height: 260px; border: 3px solid #111; border-radius: 18px; overflow: hidden; background-size: cover; background-position: center; background-repeat: no-repeat; font-family: ui-sans-serif, system-ui, sans-serif; display: grid; align-content: end; padding: 16px; } .hero p { margin: 0; width: fit-content; padding: 8px 10px; border-radius: 12px; border: 2px solid #111; background: rgba(255, 255, 255, 0.88); }
Gradient overlay + image
Pattern 3: Pseudo-element layer for opacity
This is the “I want the image faded but not the content” pattern. We place the background image on
::before, fade that layer, and keep content on top.
.panel { position: relative; overflow: hidden; }
.panel::before {
content: "";
position: absolute;
inset: 0;
background-image: url("https://picsum.photos/980/520");
background-size: cover;
background-position: center;
opacity: 0.35;
}
.panel > * {
position: relative;
}
.panel { position: relative; overflow: hidden; } .panel::before { content: ""; position: absolute; inset: 0; background-image: url("https://picsum.photos/980/520"); background-size: cover; background-position: center; opacity: 0.75; } .panel > * { position: relative; }
*, ::before, ::after { box-sizing: border-box; } .panel { width: min(720px, 100%); height: 260px; border: 3px solid #111; border-radius: 18px; font-family: ui-sans-serif, system-ui, sans-serif; padding: 18px; display: grid; align-content: end; gap: 10px; } .panel h3 { margin: 0; font-size: 20px; } .panel p { margin: 0; line-height: 1.4; background: rgba(255, 255, 255, 0.9); border: 2px solid #111; border-radius: 12px; padding: 10px 12px; width: fit-content; }
Image opacity without fading the text
The image is on ::before.
CSS background blur
“Background blur” can mean two different things:
- Blur the background behind the element (like frosted glass).
- Blur the background image you’re using (blur the wallpaper).
They’re not the same technique, so let’s do both.
Blur the background behind: backdrop-filter
backdrop-filter blurs what’s behind the element. To see the blur, the element usually needs a
semi-transparent background.
.glass { background: rgba(255, 255, 255, 0.35); backdrop-filter: blur(10px); }
.glass { background: rgba(0, 0, 0, 0.25); color: #fff; backdrop-filter: blur(16px); }
*, ::before, ::after { box-sizing: border-box; } .scene { width: min(720px, 100%); height: 280px; border: 3px solid #111; border-radius: 18px; overflow: hidden; background-image: url("https://picsum.photos/980/560"); background-size: cover; background-position: center; background-repeat: no-repeat; position: relative; font-family: ui-sans-serif, system-ui, sans-serif; } .glass { position: absolute; left: 16px; right: 16px; bottom: 16px; border: 2px solid #111; border-radius: 16px; padding: 14px; } .glass h3 { margin: 0 0 6px; font-size: 18px; } .glass p { margin: 0; line-height: 1.4; }
Frosted glass
Blur happens to what’s behind this panel.
Blur the background image itself
You can’t apply filter: blur() directly to background-image. But you can put the
background image on a pseudo-element and blur that layer.
.card { position: relative; overflow: hidden; }
.card::before {
content: "";
position: absolute;
inset: -20px;
background-image: url("https://picsum.photos/980/520");
background-size: cover;
background-position: center;
filter: blur(10px);
transform: scale(1.1);
}
.card > * {
position: relative;
}
.card { position: relative; overflow: hidden; } .card::before { content: ""; position: absolute; inset: -20px; background-image: url("https://picsum.photos/980/520"); background-size: cover; background-position: center; filter: blur(18px); transform: scale(1.2); } .card > * { position: relative; }
*, ::before, ::after { box-sizing: border-box; } .card { width: min(720px, 100%); height: 260px; border: 3px solid #111; border-radius: 18px; font-family: ui-sans-serif, system-ui, sans-serif; display: grid; place-items: center; padding: 18px; } .card .content { background: rgba(255, 255, 255, 0.9); border: 2px solid #111; border-radius: 14px; padding: 12px 14px; text-align: center; max-width: 42ch; } .card .content h3 { margin: 0 0 6px; font-size: 18px; } .card .content p { margin: 0; line-height: 1.4; }
Blurred background image layer
The blur is applied to ::before, not the text.
Common background shortcuts and best practices
In real projects, you’ll often use the shorthand:
background: color;background: url(...) no-repeat center / cover;
That second one includes position and size in one line. The syntax is: position then /
then size.
The background shorthand with position and size
.box { background: url("https://picsum.photos/980/520") no-repeat center / cover; }
.box { background: url("https://picsum.photos/980/520") no-repeat left 20px top 10px / 140%; }
.box { background: linear-gradient(90deg, rgba(0, 0, 0, 0.55), rgba(0, 0, 0, 0)), url("https://picsum.photos/980/520") no-repeat center / cover; }
*, ::before, ::after { box-sizing: border-box; } .box { width: min(720px, 100%); height: 260px; border: 3px solid #111; border-radius: 18px; overflow: hidden; font-family: ui-sans-serif, system-ui, sans-serif; display: grid; place-items: end start; padding: 16px; } .box .pill { background: rgba(255, 255, 255, 0.9); border: 2px solid #111; border-radius: 999px; padding: 6px 10px; font-size: 14px; }
Shorthand: position / size
Quick CSS Background recap and checklist
- background-color paints a color behind the element’s content.
- background-image can be a URL image or a gradient.
- background-repeat defaults to
repeat(tiling). - background-size controls the “fit” (
covervscontain). - background-position moves the background inside the element.
- There’s no
background-opacity; use alpha colors, overlays, or pseudo-elements. - For blur: use backdrop-filter to blur what’s behind, or blur a pseudo-element layer to blur the image itself.
If something looks off, the usual suspects are: repeat happening unexpectedly,
size not set (so the image tiles), or position not doing what you expect because
the image is being cropped by cover.
