Dark-Mode-Aware CSS Gradients
Most gradient guides stop at linear, radial, and conic. None of the ones checked for this piece cover what happens when the same gradient needs to look right in both a light and a dark theme.
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. That syntax exists in the specification, but real current browser support for that specific form is genuinely unclear right now, and this guide isn't going to recommend something without being sure it actually works everywhere.
The version that's reliably supported today 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?
The syntax is documented, but real current browser support for that specific form is genuinely unclear as of this writing. The custom-property approach in this guide uses light-dark() in its most basic, most reliably supported form instead.
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-platform-dx feature-tracking data, checked live this session — support for this specific form is not yet confirmed across major browsers, which is why this guide recommends the custom-property approach instead.