How to Design a Dark Mode That Doesn't Just Invert Colors

Neon sign glowing brightly against a dark night background

The fastest way to ship a dark mode is to run your light theme's colors through an inversion filter and call it done. It's also the fastest way to ship a dark mode that looks washed out, has broken contrast in half its components, and makes your brand color glow like a highlighter. Dark mode isn't a light theme with the values flipped, it's a different color system that happens to share the same layout and components.

Teams that treat it as a one-line CSS filter usually find out the hard way, after launch, when support tickets start mentioning eye strain, illegible form fields, or a logo that looks wrong against black. Getting it right takes deliberately rethinking a handful of things that don't translate from light to dark by simple inversion.

Why naive inversion breaks first

A straight inversion takes your near-white background and near-black text and swaps them, which sounds correct until you look at everything else that was tuned for a light background. Shadows that created depth on white become invisible or muddy on black. A saturated brand blue that reads as calm on white can look neon and aggressive on a near-black background, because color perception shifts with the surrounding luminance.

Semantic colors suffer the same problem. A soft red used for an error state on a white card can turn into a color that's hard to distinguish from a warning orange once the surrounding luminance drops. None of this shows up in a quick visual scan of the inverted screen, only in actual use, which is exactly why so many "we added dark mode" launches get walked back or patched within weeks.

Elevation needs light, not shadow

In a light UI, elevation, the sense that one surface floats above another, comes from shadows: a card looks raised because of the soft dark edge beneath it. On a dark background, shadows barely register, since there's already very little contrast to work with in the darker end of the value range. Dark interfaces communicate elevation the opposite way, by making higher surfaces slightly lighter rather than adding a shadow beneath them.

This is why a well-built dark mode has a small set of surface colors, background, card, elevated card, modal, each one a few percent lighter than the last, rather than a single dark color reused everywhere with shadows layered on top. Material Design's dark theme guidelines are a useful reference for this exact system, since they document the specific elevation-to-lightness mapping that makes stacked surfaces read correctly without relying on shadow at all.

Building this as a numbered scale, five or six surface tones from darkest to lightest, rather than picking colors ad hoc per component, keeps new components consistent with the rest of the interface as your product grows and more screens need an elevation level nobody had considered when the theme first shipped.

Pure black backgrounds aren't automatically correct

It's tempting to default to true black for a dark theme, since it feels like the most literal opposite of white. But pure black next to white text creates extremely high contrast that can be harsh for extended reading, and it makes anti-aliasing artifacts around text more visible than they'd be against a softer dark gray.

Most well-regarded dark themes use a very dark gray, often somewhere in the range of a few percent above pure black, rather than true black, reserving actual black for accents or for OLED-specific power-saving modes where the battery benefit outweighs the readability tradeoff. Test your specific background value against your actual text color rather than assuming either extreme is automatically right.

Saturated colors need to be desaturated, not just kept the same

A brand color tuned to look vivid on a white background will often look overly intense, even slightly glowing, against a dark background, because the eye perceives saturated colors as brighter when surrounded by darkness. The fix isn't changing the hue, it's typically reducing saturation and adjusting lightness slightly so the color reads as intentional rather than like it's fighting the background.

This applies to every semantic color in your system, not just the primary brand color. Success greens, warning yellows, and error reds all need a dark-mode-specific pass, and testing them against real content, not just a color swatch, is the only reliable way to catch the ones that don't hold up.

Contrast checking works differently against dark backgrounds

The same WCAG contrast ratio math applies in dark mode, but the specific pairs of colors that pass or fail change completely. A gray that comfortably passes AA contrast against white can fail badly against a dark background, and vice versa. Every text-and-background pairing in your dark theme needs its own contrast check, not an assumption that "if light mode passed, dark mode probably does too."

W3C's Web Accessibility Initiative publishes the current WCAG contrast guidelines, and running your actual dark-mode color pairs through a contrast checker, not just your light-mode ones, catches the failures before they ship rather than after a user reports illegible text.

Images and icons need their own dark-mode treatment

A white background image, illustration, or logo with a transparent background can look like a glaring rectangle dropped onto a dark UI. Icons drawn with thin strokes tuned for light backgrounds often look too faint against dark surfaces and need a slightly heavier stroke weight to read at the same visual size.

Plan for dark-mode-specific image assets or at least a background treatment (a subtle card or padding) for images that can't be swapped, and audit your icon set specifically at the sizes it actually ships at, not just in a large mockup where thin strokes still look fine.

Letting users choose, and respecting the system setting

Most users expect a dark mode toggle to respect their operating system's theme setting by default, with a manual override available for people who want something different from their system-wide choice. Building this with the prefers-color-scheme media query, documented on MDN, covers the default case with a few lines of CSS, and layering a manual toggle on top covers the exception case without forcing every user to make a choice they don't care about.

"The dark mode requests that come back to us after launch are almost never about the color palette itself, they're about a component nobody tested against dark: a chart, a modal overlay, a status pill that only makes sense on white. Audit component by component, not screen by screen." - Dennis Traina, founder of 137Foundry

Testing dark mode as its own design pass, not a QA afterthought

The teams that ship a dark mode without embarrassing gaps treat it as a full second design pass, reviewing every component and every semantic color against the dark palette specifically, rather than trusting an automated inversion or a quick find-and-replace on color variables. This takes real design time, but it's considerably cheaper than fixing broken contrast and glowing brand colors after launch, once real users are already reporting the problems.

web.dev has practical guidance on testing color schemes across both light and dark, including how to structure CSS custom properties so switching themes doesn't require duplicating every component's styles.

Where this fits into a broader design system

Dark mode support is easiest to add well when your design tokens are already structured around semantic roles (background, surface, text-primary, text-secondary) rather than hardcoded hex values scattered through components. If your design token system isn't there yet, that refactor is worth doing before the dark mode work itself, since it turns a sprawling audit into a smaller, centralized change.

137Foundry's web development work regularly includes exactly this kind of design system groundwork alongside feature builds like dark mode, since the two problems, scattered color values and a missing dark theme, tend to show up together. If your product needs a dark mode built the right way rather than shipped as an inversion filter, our services page has more on how we approach it, or start from the homepage or about page to see the rest of what we do.

Rolling it out without a big-bang launch

Shipping dark mode across an entire product at once is riskier than it needs to be, especially for a product with a lot of surface area. Rolling it out screen by screen or flow by flow, starting with the highest-traffic pages, lets real usage surface the components that don't hold up before the whole product depends on the new theme working correctly everywhere at once.

This staged approach also gives design and engineering room to fix the inevitable edge cases, a chart library that doesn't expose its colors as variables, a third-party widget that ships its own fixed light theme, without those specific problems blocking the rest of the rollout. Treat the first two or three screens as a pilot, gather feedback, then expand once the pattern is proven.

Maintaining it after launch

Dark mode isn't a one-time project, it's an ongoing constraint on every new component your team ships afterward. Any new feature needs its colors checked against both themes before it ships, not just the one the designer happened to have open, and that check is easy to skip under deadline pressure unless it's built into your actual review process rather than left as a good intention.

Adding a lightweight checklist item to your PR template or design review process, "reviewed in both light and dark," costs almost nothing and catches most regressions before they reach users, which is considerably cheaper than a second dark-mode audit six months after the first one.

A quarterly spot-check across a handful of representative screens, done deliberately rather than left to chance, is enough to catch the slow drift that happens as new components and third-party widgets get added over time. Smashing Magazine's archive has several practical case studies on maintaining dark themes at scale that are worth a look if your product is past the initial launch and into the maintenance phase.

Need help with Web Development?

137Foundry builds custom software, AI integrations, and automation systems for businesses that need real solutions.

Book a Free Consultation View Services