# Gradients in dark mode: keeping depth without glare

[Canonical HTML page](https://gradiently.design/guide/dark-mode-gradients)

A gradient that glows politely on white can blaze on a dark screen. Here is how to retune gradients for dark mode so they keep their depth, with CSS for prefers-color-scheme, light-dark() and a manual toggle.

## The short version

- Dark mode gradients should be redesigned for the dark theme, because the same saturated colours that look balanced on white look harsh and glaring on a dark background.
- On dark grounds, lower the chroma of gradient colours, keep bright colour to small areas, and use a near black tinted towards your brand hue instead of pure black.
- Swap gradients between themes by storing their colours in CSS custom properties and redefining them inside a prefers-color-scheme: dark media query.
- The CSS light-dark() function chooses between two colours based on the color-scheme in effect, which keeps both values next to each other.
- Dark gradients band more visibly than light ones, so a light layer of grain is worth adding in dark mode.

**Dark mode gradients** look best when you give them their own colours rather than reusing the light theme's. On a dark ground the eye adapts and every saturated colour seems brighter, so a gradient that felt calm on white starts to glare. Lower the chroma, keep vivid colour to small areas, tint the ground instead of using pure black, and switch the values with `prefers-color-scheme` or `light-dark()`. The depth stays; the glare goes.

## Why light theme gradients fail in the dark

Three things change when the page goes dark. Large bright areas become the brightest thing in the room, which reads as glare rather than colour. Shadows stop working, so gradients that relied on darkening edges for depth lose it. And the steps between dark tones get easier to see, so subtle gradients start to band. [Dark mode design](https://gradiently.design/guide/dark-mode-design) covers the wider theme; this page is about the gradients.

- Light theme hero: `linear-gradient(135deg, #ede9fe 0%, #c4b5fd 50%, #f9a8d4 100%)`
- Naive dark: full saturation: `linear-gradient(135deg, #7c3aed 0%, #db2777 100%)`
- Tuned dark: light from one corner: `radial-gradient(circle at 80% 15%, #4c1d95 0%, #1a1530 45%, #0b0a14 85%)`

The same brand gradient three ways. The middle one is what happens when a light design is simply darkened: loud, flat, tiring. The last keeps the violet but lets it glow from a corner over a tinted ground.

## Five rules for dark mode gradients

1. **Tint the ground** Use a near black that leans towards your hue, such as `#0b0a14` for violet brands, instead of `#000000`. Pure black makes colour look pasted on.
2. **Lower chroma** Pull saturation down by roughly a third for large areas. In OKLCH, keep the hue and reduce the C value.
3. **Shrink the bright part** Let vivid colour occupy a corner or a glow, and let most of the surface sit close to the ground.
4. **Lift, do not shadow** Show elevation with slightly lighter surfaces and gradients that brighten towards the top, since shadows disappear on dark grounds.
5. **Add grain** Fine noise breaks up the visible steps in dark blends. [Grainy gradients](https://gradiently.design/guide/grainy-gradients) has the recipe.

- Ground: #0b0a14
- Surface: #1a1530
- Raised: #2a2148
- Deep violet: #4c1d95
- Accent: #8b5cf6
- Text accent: #c4b5fd

A dark gradient set for a violet brand. Most of the screen uses the first three; the accent appears in small places, and the pale lilac is reserved for text and icons.

## Switching gradients with prefers-color-scheme

Store gradient colours, not whole gradients, in custom properties. Then the dark theme only has to redefine the colours, and every component that uses them updates. This is the same pattern described in [CSS variables for theming](https://gradiently.design/guide/css-custom-properties-theming).

```css
:root {
  color-scheme: light dark;
  --ground: #faf8ff;
  --glow: #c4b5fd;
  --glow-2: #f9a8d4;
  --hero: radial-gradient(circle at 80% 15%, var(--glow) 0%, transparent 45%),
          radial-gradient(circle at 10% 90%, var(--glow-2) 0%, transparent 50%),
          var(--ground);
}

@media (prefers-color-scheme: dark) {
  :root {
    --ground: #0b0a14;
    --glow: #4c1d95;
    --glow-2: #1e3a8a;
  }
}

.hero {
  background: var(--hero);
}
```

Because --hero and its colours live on the same element, redefining the colours in the media query updates the gradient everywhere it is used. color-scheme also tells the browser to darken scrollbars and form controls.

Notice the dark glows are deeper, not brighter. On a dark ground a colour only needs to be a little lighter than its surroundings to read as light.

### Using light-dark()

The `light-dark()` function returns its first colour in a light scheme and its second in a dark one. It needs `color-scheme: light dark` on the element or an ancestor, and it is supported in current Chrome, Edge, Safari and Firefox. It keeps both values on one line, which makes reviewing a palette easier.

```css
:root {
  color-scheme: light dark;
}

.card {
  background: linear-gradient(
    180deg,
    light-dark(#ffffff, #1a1530) 0%,
    light-dark(#f5f3ff, #0b0a14) 100%
  );
  color: light-dark(#1e1b2e, #e9e5f5);
}
```

In current browsers light-dark() takes colours, not images, so use it for each stop rather than for the whole gradient.

### Supporting a manual theme toggle

Many sites let people override the system setting. Put the choice on the root element and scope your variables to it. The media query handles the default; the attribute wins when someone chooses.

```css
:root[data-theme="dark"] {
  color-scheme: dark;
  --ground: #0b0a14;
  --glow: #4c1d95;
  --glow-2: #1e3a8a;
}

:root[data-theme="light"] {
  color-scheme: light;
}
```

Setting color-scheme to a single value also makes light-dark() follow the toggle.

## Retuning a gradient for dark mode

Here is the same brand gradient adjusted stop by stop. Working in OKLCH makes this predictable, because lightness and chroma are separate numbers; [OKLCH explained](https://gradiently.design/guide/oklch-explained) shows why.

| Stop | Light theme | Dark theme | Change |
| --- | --- | --- | --- |
| Ground | `oklch(98% 0.01 295)` | `oklch(15% 0.03 295)` | Tinted near black, not black |
| Main | `oklch(85% 0.09 295)` | `oklch(35% 0.15 295)` | Darker, chroma kept moderate |
| Accent | `oklch(84% 0.10 350)` | `oklch(40% 0.12 265)` | Shifted cooler to avoid a hot pink blaze |
| Text accent | `oklch(45% 0.20 295)` | `oklch(82% 0.09 295)` | Lighter and softer for small text |

Hue stays where it is for the main colours, so the brand still reads as itself in both themes.

Dark theme hero, in OKLCH: `radial-gradient(circle at 80% 15%, oklch(35% 0.15 295) 0%, transparent 45%), radial-gradient(circle at 10% 90%, oklch(40% 0.12 265) 0%, transparent 50%), linear-gradient(oklch(15% 0.03 295), oklch(15% 0.03 295))`

The dark values from the table, layered. Copy it, then nudge chroma until the glow feels warm rather than bright.

## Text on dark gradients

Light text on a dark gradient usually has plenty of contrast, but check it where the gradient is brightest, not where it is darkest. A headline in `#e2e8f0` on `#0b0a14` is far above the 4.5:1 that WCAG asks for body text; the same headline over a bright violet glow may not be. Avoid pure white body text on near black as well: very high contrast causes halation for some readers, so a soft off white is kinder. [Colour contrast and accessibility](https://gradiently.design/guide/color-contrast-accessibility) has the numbers.

### Avoid in dark mode

- Pure black ground with saturated stops
- The light theme gradient, darkened
- Large areas of neon colour
- Pure white paragraphs
- Smooth dark gradients with no grain

### Do

- A tinted near black ground
- A separate set of dark stops
- Colour as light from one corner
- Off white text, around `#e9e5f5`
- A fine noise layer to hide banding

For more dark palettes, [dark gradient backgrounds](https://gradiently.design/guide/dark-gradient-backgrounds) has a set to copy. And for social posts and slides, where you cannot test every line by hand, Gradiently's Auto ink picks light or dark type per line from the Mark's own palette, and the Mark moves its calmest area behind the words, so a dark design never puts a headline on its brightest glow.

## FAQ

### How do I change a gradient in dark mode?

Put the gradient's colours in CSS custom properties and redefine them inside `@media (prefers-color-scheme: dark)`. The gradient updates wherever it uses those variables.

### Can I use light-dark() inside a gradient?

Yes, for each colour stop, since light-dark() returns a colour. It needs `color-scheme: light dark` on the element or an ancestor.

### Why do my gradients look too bright in dark mode?

Eyes adapt to dark screens, so saturated colours seem stronger. Lower the chroma, darken the stops and keep bright colour to small areas.

### Should dark mode use pure black?

Usually not for gradients. A near black tinted towards your brand hue makes colours blend naturally and reduces harsh contrast.

### Why does my dark gradient show stripes?

Dark tones sit close together in 8 bit colour, so steps become visible. Add a light grain layer and avoid heavy compression.
