Dark mode isn't just flipping a colour palette. When I started building Spectral, I assumed it'd be a two-hour task. Six weeks later, I had a completely rethought approach to colour, contrast, and depth that changed the way I design for Android.

The naive approach (and why it fails)

My first attempt was exactly what you'd expect: take every light colour, invert it, done. White backgrounds became near-black. Dark text became near-white. I shipped it to a handful of beta users and within 48 hours the feedback was unanimous - it looked harsh, clinical, and nothing like the premium feel I was going for.

The problem is that human perception isn't linear. A white card on a light grey background creates a subtle sense of elevation. Invert that and you get a black card on a slightly-lighter-black background - and the depth completely disappears.

"A good dark mode doesn't feel like a light mode that had the lights turned off. It feels like it was designed in the dark."

Elevation through lightness, not shadow

In Material 3's dark theme guidelines, Google documents something counter-intuitive: in dark mode, elevated surfaces should be lighter, not darker. A card that floats above the background should use a slightly higher lightness value - maybe #1e1e2e against a base of #12121f.

This mirrors how light actually works. In a dark room, objects closer to a light source pick up more of that light. Depth means brightness, not shadow.

For Spectral I ended up with a four-level elevation system:

The differences are subtle. That's the point. If a user consciously notices the layers, the gradation is too aggressive.

Colour saturation in dark contexts

The purple accent I use throughout Spectral was born in a light-mode prototype. Dropped into a dark background, it screamed. The solution isn't to desaturate - that kills vibrancy - it's to reduce chroma while preserving hue.

Working in the OKLCH colour space made this straightforward. Instead of adjusting HSL sliders and eyeballing the result, I could dial the C (chroma) value down incrementally while keeping L and H fixed. The result: a purple that still reads as purple, but doesn't assault the eyes at 2am.

Text contrast: the 4.5:1 trap

WCAG AA requires 4.5:1 contrast for normal text. This is a floor, not a target. On a dark background, pure white at 21:1 contrast is technically correct and visually exhausting. I settled on three text levels:

The takeaway

Dark mode is a first-class design problem, not an afterthought. The apps that get it right share one thing in common: their dark mode looks like it was designed in the dark, from scratch. Not like a light mode that got inverted.

For Spectral, the six weeks I spent on this turned out to be some of the highest-leverage design work in the project. Users don't comment on the elevation system or the OKLCH adjustments. They just say it feels polished. That's the goal.