The first layer in the list paints on top
This trips up almost everyone the first time. In background-image, the first value in the comma separated list sits nearest the visitor and every later value stacks behind it. The base colour sits behind all of them. The panel above labels the first card Top and the last one Base so the order on screen matches the order in the rule.
background-image:linear-gradient(180deg,transparent, rgba(11,17,32,0.8)),url("hero.avif");background-image:url("hero.avif"),linear-gradient(180deg,transparent, rgba(11,17,32,0.8));Both rules are valid and both load the same photo. The one on the right paints an opaque photo across the whole box, so the gradient behind it never shows a pixel. When a wash you wrote refuses to appear, the order is the first thing to check.
Why the dark wash exists
White text on a photograph reads fine over the sky and vanishes over the pale wall in the corner. Contrast is measured against the pixels behind each letter, and a photo gives you no control over those pixels. A gradient layer between the photo and the text gives back that control: the bottom of the box gets a known colour, so the headline sits at a contrast ratio you measured once instead of one that shifts when the photo is swapped.
Three habits keep this honest:
- Fade to a colour rather than to black. A wash in the same family as the photo looks deliberate, while flat black over a warm image reads as a mistake.
- Start the gradient at zero alpha and end near 80 percent. A wash at full opacity across the whole box means you did not need the photo at all.
- Test the headline over the busiest corner, not the calm one. Turn on Sample text above, drag the box narrow, and watch what happens when the photo is cropped by
coveron a phone.
Blend modes do a different job. multiply pushes a colour into the shadows of the photo, screen lifts the highlights, and luminosity strips a photo down to greyscale while a colour layer below tints it. They blend against the layer beneath, so a blend mode on a lone layer only ever interacts with the base colour.
Every background property takes a list
Once there are two images, the other background properties become lists too, matched by position: the first background-size belongs to the first image, the second to the second. A short list repeats itself to cover the images, which is where surprising results usually come from.
| Property | What it does per layer | Worth knowing |
|---|---|---|
| background-size | cover fills the box and crops, contain fits the whole image and leaves gaps, two values set width and height directly. | Gradients respond to size the same as photos. A radial gradient at 70% 70% becomes a soft spotlight instead of a wash. |
| background-position | Anchors the image inside the painting area. Percentages align the same point of the image with that point of the box. | With cover, position decides what survives the crop. Faces near an edge want top rather than center. |
| background-repeat | Tiles the image. space distributes whole tiles with gaps, round stretches them so a whole number fits. | Only worth setting on a tile whose edges line up. A photo set to repeat shows its seams down the middle of the box. |
| background-attachment | scroll moves with the box, fixed pins the image to the viewport, local follows the content of a scrolling box. | fixed repaints on every scroll frame and iOS Safari ignores it inside scrolling containers. That is the whole story behind broken parallax on iPhones. |
| background-blend-mode | Blends each layer with the layers below it inside the same element. | Different from mix-blend-mode, which blends the whole element with the page behind it. |
| background-origin / clip | Decides whether painting starts at the border, the padding edge or the content box. | Not generated here. Add them by hand when a dashed border needs to sit clear of the image. |
The shorthand packs one layer per comma with the syntax image position/size repeat attachment. One rule to remember: background-color is allowed only in the final layer, and the shorthand resets every property it leaves out. Writing background: url(a.png) after a background-repeat line silently throws that repeat away. The longhand tab avoids the whole problem, which is why it is the default here.
When a background image is the wrong tool
A CSS background is decoration. The browser gives it no alternative text, screen readers skip it, and it stays invisible to image search. Anything a reader needs in order to follow the page belongs in an <img> tag with an alt attribute: product photos, charts, portraits, screenshots in a tutorial.
- Above the fold, an
<img>loads sooner. Background images are found only after the CSS parses and the element matches, so they start late and often become the slowest paint on the page. A real<img>withfetchpriority="high"is discovered by the preload scanner in the first pass of the HTML. - Art direction wants
<picture>. Serving a tight upright crop to phones and a wide one to desktops is one<source>element. In CSS it is a media query per breakpoint, repeated for every format you ship. - Small icons belong inline. A single decorative shape is usually smaller as an inline SVG than as a request, and inline SVG takes
currentColorso it follows the text.
Backgrounds win when the artwork is decorative, when it has to sit behind live text, when it tiles, or when it is generated by gradients and costs no request at all. The dot grid and stripe presets above are the second case: pure CSS, no download, and they scale to any screen density.
Formats, density and the parts this page skips
Everything here runs in your browser and nothing you paste is uploaded. Four things the output deliberately leaves out, each because guessing at them tends to produce code people delete later:
- Format fallbacks.
image-set()lets you offer AVIF with a JPEG behind it and a 2x file for dense screens. Support is wide now, though the older-webkit-image-set()prefix still matters for a few browsers in the wild. - Media queries. Phones rarely want the desktop crop. Build the phone version here, copy it into a breakpoint, then build the desktop version and copy that one.
- Colour scheme variants. A wash tuned for light mode is usually too weak in dark mode. Generate both and split them with
prefers-color-scheme. - Multi stop gradients. Each gradient layer here takes two colours. For a three or four stop ramp, or for colour interpolation in
oklch, use the CSS gradient generator and paste the value into an image layer.
The photo preset uses an inline SVG placeholder, not a stock image. It keeps the preview working offline and keeps the tool free of a third party host. Swap the URL for your own asset before shipping. If the preview stays blank after you paste a real URL, the file is almost always blocked by hotlink protection or by a CORS rule on the origin, not broken CSS.
