PaletteGen
Theme

Dark-Mode-Aware CSS Gradients

How to make one CSS gradient look right in both a light and a dark theme, without it washing out or clashing.

By , PaletteGen

About 3 min read · Last reviewed

Short answer: Set each gradient color stop as its own custom property using light-dark(), then write one normal gradient that references those properties. The gradient never changes, only the colors it resolves to.

A gradient built for a light background usually looks wrong on a dark one. Not subtly wrong, actually broken: washed out, too pale to read against, or clashing with everything around it. If a site supports both themes, every gradient on it needs a light version and a dark version, not one gradient that gets left behind when the theme switches.

The reliable way to do this today

It's tempting to wrap an entire gradient declaration in light-dark(), swapping the whole thing at once. As of September 2026 that works: light-dark() accepts image values, including url() and gradients, and web.dev lists it as Baseline Newly available (Chrome and Edge 150, Firefox 150, Safari 27). Older browsers ignore it, so this guide leads with a pattern that also works in the browsers before those releases.

The version that works in every browser with light-dark() support uses light-dark() for what it was built for first and most solidly: choosing between two plain color values. Define each color stop as its own custom property, and let light-dark() pick the right one:

:root {
  --grad-start: light-dark(#0891B2, #00FFFF);
  --grad-end:   light-dark(#FAFAFC, #0F0F1A);
}

.hero {
  background: linear-gradient(135deg, var(--grad-start), var(--grad-end));
}

The gradient declaration itself never changes. Only the colors it resolves to do, automatically, the moment the color scheme switches: no media query, no JavaScript, no duplicate gradient rule to keep in sync.

Don't just invert the gradient's lightness

The same principle from choosing dark-mode colors generally applies here too: mechanically flipping a light gradient's lightness values tends to produce a muddy, low-contrast dark version, not a genuinely good one. Pick the dark-mode stop colors deliberately (adjust hue and saturation, not just lightness) using the same framework this site's own guide to choosing dark mode colors already lays out for solid colors. The same thinking applies whether the color is sitting alone or inside a gradient stop.

Building the actual gradient

Design the light and dark versions of a palette using this site's own color palette generator or the light-dark() generator, then bring the resulting hex pairs into the custom-property pattern above. The gradient generator itself doesn't currently build the light-dark pairing for you automatically, but it's the fastest way to preview what a given stop sequence and angle will actually look like before wiring it into the pattern here.

Frequently Asked Questions

Can I put light-dark() directly around a whole gradient?

Yes, in current browsers. As of September 2026, light-dark() accepts image values, including gradients, in Chrome and Edge 150, Firefox 150 and Safari 27. Older browsers ignore it, so the custom-property approach in this guide is the safer pattern when you need to support them.

Do I need two separate gradient declarations for light and dark mode?

No. Define each color stop as a custom property using light-dark(), then write one normal gradient that references those custom properties. The gradient itself never changes, only the colors it resolves to.

Will this work without JavaScript?

Yes. light-dark() responds to the CSS color-scheme property, which follows the operating system or browser preference automatically, no script required.

Sources

  • light-dark() function syntax, accepted value types, and Baseline statusMDN Web Docs, light-dark() CSS function reference.
  • Current browser support status for light-dark() with image/gradient values specificallyweb.dev, "New to the web platform in September" (2026): light-dark() with image values is Baseline Newly available in Chrome and Edge 150, Firefox 150 and Safari 27. The custom-property pattern remains the fallback for older browsers.

About this page

The light-dark() syntax and Baseline status come from MDN. Support for light-dark() with gradient values changed recently, so web.dev's September 2026 roundup was checked when this page was updated, and it keeps the custom-property pattern as the fallback for older browsers.