Skip to content
Miru 3.0 is here — expenses, CLI, dark mode, and 6 report types. Read the announcement →
Engineering Design

Dark Mode Done Right: Why Most Apps Get It Wrong

CSS invert() is not dark mode. Here's what it actually takes to build a dark theme that doesn't hurt your eyes.

Saeloun Team · · 3 min read

Most dark modes are terrible. Not because dark mode is a bad idea — it’s a great idea. They’re terrible because the developers who built them took a shortcut and nobody called them on it.

The shortcut looks like this:

@media (prefers-color-scheme: dark) {
  html { filter: invert(1) hue-rotate(180deg); }
}

One line. “Dark mode” done. Ship it. Blog about it. Move on.

Except it looks awful. Images are inverted. Shadows go backwards. Borders that worked on white backgrounds become invisible on dark ones. Brand colors shift. The whole thing has an uncanny valley quality where everything is technically visible but nothing feels intentional.

This is the CSS equivalent of turning your shirt inside out and calling it a new outfit.


What actually goes wrong

Contrast ratios break. A light gray text that had a 4.5:1 contrast ratio on white backgrounds now has a 2:1 ratio on the inverted dark background. You’ve made the app harder to read, not easier. Accessibility compliance goes out the window — the same WCAG ratios that passed in light mode fail in dark mode.

Shadows and elevation disappear. In light mode, shadows create depth. In dark mode, shadows are invisible against dark backgrounds. You need to replace shadow-based depth cues with lighter borders or subtle glows. An inverted theme does neither — it just makes shadows disappear, flattening the entire interface.

Colors don’t translate. A vibrant blue button on a white background looks great. That same blue on a dark gray background can be jarring, too bright, or visually overwhelming. Good dark mode requires adjusting saturation and brightness for every accent color, not just flipping the lightness channel.

Images and media get destroyed. The invert() filter catches everything in the DOM. Your product screenshots, your team photos, your logo — all inverted. So you add img { filter: invert(1); } to cancel it out. Now you’ve got two filter operations on every image, and you’re still dealing with edge cases in SVGs, canvas elements, and CSS backgrounds.


How we built Miru’s dark mode

We didn’t use any automated transforms. Every color in Miru’s dark mode was chosen specifically for dark backgrounds.

Separate color tokens. We maintain two sets of design tokens — light and dark. Background colors, text colors, border colors, accent colors, shadow values. When dark mode is active, the entire token set swaps. No filters. No calculations. Explicit values chosen by a human looking at a screen.

Tested contrast ratios on both themes. Every text-on-background combination meets WCAG AA in both light and dark mode. Some colors that work in light mode were replaced entirely in dark mode because they couldn’t be adjusted to pass without looking wrong.

Replaced shadows with borders. The card elevation system in light mode uses subtle box-shadows. In dark mode, those same cards use a 1px border with a slightly lighter shade. The visual hierarchy is preserved but the mechanism is completely different.

Designed, not derived. The invoice editor, the time tracking calendar, the report charts, the settings pages, the modals — every one was reviewed in dark mode by a designer who made intentional choices. Not by an algorithm that did a color math.


The uncomfortable truth

Building a good dark mode takes about 30% of the effort of the entire UI. It’s not a toggle. It’s not a filter. It’s a second visual design system that shares layout and structure with the first but differs on nearly every aesthetic decision.

Most teams don’t do this because it’s expensive. They’d rather ship filter: invert(1) and check the “dark mode” box on their feature comparison page. The users who care about dark mode — developers, night owls, people with light sensitivity — can tell the difference immediately.

We spent the time because we’re those users. We review invoices at 11 PM. We log time before sunrise. We stare at screens for 10+ hours a day. A real dark mode isn’t a feature. It’s basic respect for the people using your software.

Toggle it in Miru’s preferences. It remembers your choice. Your eyes will thank you.

Share:
ST

Saeloun Team

The team behind Miru. Ruby on Rails consultancy turned product company. Based in Pune, India.

Try Miru today

Free to start. No credit card required.

Start Tracking Free