CSS Background Generator
Generate mesh gradients, repeating patterns — stripes, dots, grids, zigzag — and blend-mode backgrounds in pure CSS, with no image files needed.
`transparent` is not "no colour" — it is transparent black
The keyword is defined as rgba(0, 0, 0, 0). The alpha is what you wanted; the
three zeros come along with it. On its own that never matters, because a fully transparent
colour paints nothing whatever its channels say.
In a gradient it matters a lot. The mesh presets on this page fade radial gradients out to
transparent, and if an engine interpolates the channels and the alpha
separately then halfway between red and transparent-black is half-transparent
dark red. Composited over a white page:
| Position | Interpolated naively | Premultiplied |
|---|---|---|
| 0% | rgb(255, 0, 0) | rgb(255, 0, 0) |
| 25% | rgb(207, 64, 64) | rgb(255, 64, 64) |
| 50% | rgb(191, 128, 128) | rgb(255, 128, 128) |
| 75% | rgb(207, 191, 191) | rgb(255, 191, 191) |
| 100% | rgb(255, 255, 255) | rgb(255, 255, 255) |
The red channel starts at 255, falls to 191 at 47%, and comes back to 255. It is not monotone — a dip of 64 below both of its own endpoints. That dip is the muddy grey band people used to complain about.
Premultiplying fixes it: weight each colour by its own alpha before interpolating and divide back out afterwards, and a colour with zero alpha contributes nothing, so it cannot drag the hue anywhere. The red channel then stays flat at 255 the whole way — the colour stays red and only the alpha changes, which is what "fade out" was always supposed to mean. Current engines do this, so the band is largely history.
Why nobody noticed on dark themes
I assumed the difference would be smaller over a dark background. It is not:
| Background | Widest gap between the two methods | At |
|---|---|---|
| white | 64 out of 255 | 47% |
| black | 64 out of 255 | 45% |
Exactly the same number. What changes is the shape of the curve, and that is what the eye picks up:
| Position | Naive, over black | Premultiplied, over black |
|---|---|---|
| 0% | rgb(255, 0, 0) | rgb(255, 0, 0) |
| 25% | rgb(143, 0, 0) | rgb(191, 0, 0) |
| 50% | rgb(64, 0, 0) | rgb(128, 0, 0) |
| 75% | rgb(16, 0, 0) | rgb(64, 0, 0) |
| 100% | rgb(0, 0, 0) | rgb(0, 0, 0) |
Over black both versions fall straight to zero. The naive one falls faster — it goes as the square of the remaining alpha rather than linearly — so it reads as a fade that finishes early rather than one that goes wrong. Same size of error, no band, and nobody files a bug about it. On white the curve doubles back on itself, and a band darker than the colours on either side of it is exactly what looks like dirt.
The habit worth keeping anyway
Write the fade endpoint as the same colour with zero alpha rather than the keyword:
rgba(255, 0, 0, 0) instead of transparent.
| Position | to transparent | to rgba(255,0,0,0) |
|---|---|---|
| 0% | rgb(255, 0, 0) | rgb(255, 0, 0) |
| 25% | rgb(207, 64, 64) | rgb(255, 64, 64) |
| 50% | rgb(191, 128, 128) | rgb(255, 128, 128) |
| 75% | rgb(207, 191, 191) | rgb(255, 191, 191) |
| 100% | rgb(255, 255, 255) | rgb(255, 255, 255) |
Naming the colour makes even the naive interpolation correct, because both endpoints now have the same channels and only the alpha is moving — there is nothing left for the interpolation to get wrong. It costs nothing, it says what you mean, and it produces the same result in every engine that has ever existed rather than only in current ones.
How to use
- Choose a pattern or gradient type.
- Adjust the colours, size and angle.
- Check how it tiles at different sizes.
- Copy the generated CSS.
Frequently asked questions
How do you make a pattern without an image?
With repeating gradients. Placing two colour stops at the same position creates a hard edge rather than a fade, and repeating that produces stripes; layering repeating gradients at different angles produces grids, checks and zigzags. It is all one background property and no network request.
Why use CSS rather than an image file?
No extra request, no file to cache, infinite resolution at any zoom, and colours that can be changed by a custom property rather than by re-exporting. The trade-off is that complex patterns become hard to read in source form, and genuinely intricate artwork is better as an SVG.
What is a mesh gradient?
Several radial gradients layered at different positions, blending into each other to produce soft multi-directional colour. CSS has no true mesh gradient, so this is an approximation — a convincing one for backgrounds, and not a substitute for the real thing in design software.
What do blend modes do?
Control how layers combine rather than simply stacking. Multiply darkens, screen lightens, overlay increases contrast. They let two simple gradients produce something considerably richer than either alone, and they are also how a texture is tinted without editing the texture.
Do complex backgrounds cost performance?
Large blurred or heavily layered backgrounds have a real paint cost, particularly on scroll or resize. A static background paints once and is cheap thereafter; one that animates or moves with scroll is the case to watch on modest hardware.
Will text be readable over a pattern?
Often not, and it needs deliberate handling. A busy background defeats contrast checking, since the ratio varies pixel to pixel. The reliable approaches are a solid or semi-transparent panel behind the text, or restricting the pattern to areas that carry no text.
🔒 This tool runs entirely in your browser. Nothing you enter is uploaded, logged, or stored.