Pure flat fills are easy. The gradients in real dark UIs are less so — get them wrong and they band, run the wrong direction, or fight the foreground. This page is a short field reference: enough syntax to write the gradient you want, plus the corner cases that actually come up.

The two functions you need

CSS has several gradient functions. For dark backgrounds, two of them do almost all the work:

conic-gradient() exists, and repeating-linear-gradient() is useful for stripes, but on black backgrounds you rarely reach for either; the first reads as a colour wheel, the second as graphic stripes.

Linear: angle, stops, and the "where does it start"

The first argument is direction. Two equivalent ways to write the same fade:

/* keyword direction — readable, prefer this */
.bg-fade {
  background: linear-gradient(to bottom, #000, #1a1a1a);
}

/* angle direction — 180deg also points down */
.bg-fade {
  background: linear-gradient(180deg, #000, #1a1a1a);
}

CSS angles in linear-gradient use a clockwise convention starting from "up": 0deg is up, 90deg right, 180deg down, 270deg left. This is the opposite of mathematical convention and the source of most "why is my gradient sideways?" bugs.

Stops let you control where colours land along the line:

.bg-fade {
  background: linear-gradient(180deg,
    #000     0%,
    #000     40%,
    #1a1a1a 100%);
}

Repeating a colour at two stops creates a flat region — the example above is "pure black for the top 40%, then fade". Use this to push the gradient out of the area where headlines sit, so they read against a flat field.

Radial: ellipse vs circle, position, sizing

Radial gradients are the workhorse for "spotlight" looks on dark heroes:

.bg-spotlight {
  background:
    radial-gradient(ellipse at center,
      #2a2a2a 0%,
      #000 70%);
}

Three things to know:

Easing approximation: avoiding banded transitions

CSS gradients interpolate linearly between stops. The eye does not see brightness linearly, so a gradient between two near-black colours looks "stepped" or banded in the middle range. There are two practical fixes.

Multi-stop approximation

Insert intermediate stops so the perceived curve is closer to ease-out:

.bg-smoother {
  background: linear-gradient(180deg,
    #000     0%,
    #050505 25%,
    #0a0a0a 50%,
    #121212 75%,
    #1a1a1a 100%);
}

Five stops is usually enough. Going beyond ten is wasted effort.

Native interpolation hints

Modern browsers support an interpolation hint — a single percentage between two stops that biases the curve:

.bg-eased {
  background: linear-gradient(180deg,
    #000 0%,
    65%,        /* push the midpoint toward the dark end */
    #1a1a1a 100%);
}

Combine this with the grain technique to fully eliminate visible bands on cheap displays.

Layering: gradient + pattern + colour

CSS lets you stack multiple backgrounds in one declaration. The first one listed paints on top:

.hero {
  background:
    radial-gradient(ellipse at center,
      rgba(255,255,255,0.05) 0%,
      transparent 60%),
    linear-gradient(180deg, #000, #0a0a0a);
}

This is a near-black page with a faint centre highlight. The first gradient uses an alpha channel so it can lift the colour underneath rather than replacing it.

The same trick is what powers the generator's pattern overlays: a vector or canvas-rendered pattern sits on top of a flat or gradient base. If you are exporting CSS straight from the generator, the layered background declaration that comes out is exactly this shape — a pattern layer over a base colour.

Blend modes

Two properties matter:

For dark backgrounds, the useful blend modes are screen (lifts dark values, useful for adding glow), overlay (preserves blacks while increasing midtone contrast) and soft-light (gentle texture without changing the overall tone). Avoid multiply — it crushes near-black to pure black and amplifies banding.

Performance and paint cost

Gradient backgrounds are nearly free at paint time on every modern browser. The performance trap is animating a gradient by changing one of its stop colours — that triggers a full repaint of the painted area on every frame. If you need a moving gradient effect, animate background-position on a larger-than-viewport gradient, or use a CSS custom property and let the browser interpolate it.

Fallbacks worth keeping

Browsers without gradient support are essentially extinct as of the mid-2020s, but the one fallback worth keeping is a solid background-color sitting underneath the background shorthand:

.hero {
  background-color: #0a0a0a;          /* fallback */
  background:                          /* layered, gradients */
    radial-gradient(ellipse at center,
      rgba(255,255,255,0.05) 0%,
      transparent 60%),
    linear-gradient(180deg, #000, #0a0a0a);
}

If the rendering engine fails any single layer, the box still has a sensible dark colour. This is also the right pattern for emails and printable PDFs, where gradient support is unreliable.

Common mistakes

  1. Gradient in the wrong direction. Remember 0deg is up, not right.
  2. Two near-identical near-blacks. A gradient between #000 and #020202 is invisible; you wrote a flat fill with extra steps.
  3. Using multiply blend mode for "depth". It crushes the gradient and amplifies banding. Use overlay or soft-light.
  4. Layering pure-black gradient stops where you wanted near-black. See pure vs near-black — for body text surfaces, end the gradient at #0a0a0a rather than #000.
  5. Animating gradient stops directly. Animate background-position on an oversized gradient instead.

What to do next

Open the generator, switch the background type to "Linear" or "Radial", and use the matrix view to compare gradients quickly. Copy the CSS from any tile via the "Show CSS" button. If the result bands on your monitor, see grain and banding; if you are pairing the gradient with a pattern, the pattern guide covers density. For body-text surfaces, finish the gradient at the values from pure vs near-black.

Last reviewed on 28 April 2026.

← Back to generator