Austin Hagel

Contact Me

Dark Mode Done Right

Dark mode sounds simple until you actually implement it. Here's everything that needs to work together to get it right.

The Four Requirements

1. System preference — respect prefers-color-scheme by default 2. User override — let users toggle and remember their choice 3. No flash on load — the page should render in the correct mode immediately 4. Nice transition — the switch should feel intentional, not jarring

1. The CSS Foundation

Use a data-color-scheme attribute on <html> as your styling hook, with a prefers-color-scheme fallback:

```css :root { color-scheme: light dark; }

:root, [data-color-scheme='light'] { --bg: oklch(97% 0.01 260); --fg: oklch(20% 0.04 260); }

[data-color-scheme='dark'] { --bg: oklch(18% 0.04 260); --fg: oklch(92% 0.01 260); }

@media (prefers-color-scheme: dark) { :root:not([data-color-scheme='light']) { --bg: oklch(18% 0.04 260); --fg: oklch(92% 0.01 260); } } ```

The :not([data-color-scheme='light']) selector ensures a user's explicit light-mode choice is respected even in a dark OS environment.

2. No Flash on Load

Run a small inline script in <head> — before any CSS loads — to apply the stored preference:

`html <script> const stored = localStorage.getItem('color-scheme'); if (stored) { document.documentElement.dataset.colorScheme = stored; } </script> `

Inline, synchronous, tiny. No flash.

3. The Toggle

```javascript function toggleTheme() { const current = document.documentElement.dataset.colorScheme; const isDark = current === 'dark' || (!current && window.matchMedia('(prefers-color-scheme: dark)').matches);

const next = isDark ? 'light' : 'dark'; document.documentElement.dataset.colorScheme = next; localStorage.setItem('color-scheme', next); } ```

4. The Transition

A crossfade is fine. A circular reveal from the button click is better. See my View Transitions API post for the full implementation.

The short version: document.startViewTransition() + clip-path animation on ::view-transition-new(root).

Don't Forget

An egg cracked into a bowl of flour surrounded by baking ingredients including bread, eggs, and a whisk
An egg cracked into a bowl of flour surrounded by baking ingredients including bread, eggs, and a whisk

Comments

Loading comments…