Skip to content

Dark Mode

The quickest dark mode is an inversion: white backgrounds turn black, black text turns white, and everything else stays. It looks wrong in ways that are hard to name. Cards vanish into the page, the menu has no edge, and the brand blue buzzes against the black.

Design dark mode as its own theme: lift surfaces with lightness, soften the extremes, and recheck every color.

Text21.0:1Link3.2:1

Inverted, the page, the card and the menu are all #000, and the light mode shadows have nothing left to darken. Text is pure white at 21:1, so bright it glows, while the light mode link drops to 3.2:1. The designed version uses this site's values: a 0.17 page, a 0.205 card, text at 0.945, plus a 0.24 menu and an accent raised to 0.72 lightness with about half the chroma. Text lands at 15.3:1 and the link at 7.1:1.

Apple puts it simply: dark colors "aren't necessarily inversions of their light counterparts."

Lighter means closer

In light mode, shadows show what sits on top. On a dark page there is little left to darken, so elevation comes from the surface instead: the higher a layer, the lighter it gets. Material's dark theme and Apple's base and elevated backgrounds both work this way.

At +0.000 only shadows separate the layers, and they barely do. At +0.035 per level, the step this site takes from page to card, every layer reads at a glance. Push past +0.05 and the menu starts to look gray rather than dark. Keep the shadows anyway: here they carry a faint inset highlight along the top edge, as in shadows, not borders.

Recheck the rest

  • Accents: saturated colors vibrate on dark backgrounds. Raise the lightness, lower the chroma, and measure contrast again, because a color that passed on white can fail on dark gray.
  • Text weight: light text on dark renders heavier on macOS. See font smoothing.
  • The canvas: paint the root background too, or overscroll shows a white strip. See HTML background.
  • Browser UI: color-scheme: dark makes scrollbars, form controls and the default canvas dark as well.

Usage

styles.css
@import "tailwindcss";

@theme {
  --color-page: oklch(0.985 0 0);
  --color-card: oklch(1 0 0);
  --color-popover: oklch(1 0 0);
  --color-ink: oklch(0.205 0 0);
  --color-accent: oklch(0.52 0.18 265);
}

:root {
  color-scheme: light;

  @variant dark {
    color-scheme: dark;
    --color-page: oklch(0.17 0 0);     /* not #000 */
    --color-card: oklch(0.205 0 0);    /* one step up */
    --color-popover: oklch(0.24 0 0);  /* two steps up */
    --color-ink: oklch(0.945 0 0);     /* not #fff */
    --color-accent: oklch(0.72 0.12 265);
  }
}

/* <body class="bg-page text-ink antialiased"> */
:root {
  color-scheme: light dark;
  --page: oklch(0.985 0 0);
  --card: oklch(1 0 0);
  --popover: oklch(1 0 0);
  --ink: oklch(0.205 0 0);
  --accent: oklch(0.52 0.18 265);
}

@media (prefers-color-scheme: dark) {
  :root {
    --page: oklch(0.17 0 0);
    --card: oklch(0.205 0 0);
    --popover: oklch(0.24 0 0);
    --ink: oklch(0.945 0 0);
    --accent: oklch(0.72 0.12 265);
  }
}

html {
  background: var(--page);
  color: var(--ink);
}

With a manual theme toggle, set color-scheme from the same switch that swaps your colors, or a dark page ships with light scrollbars. next-themes, which this site uses, writes it on the root element for you.

Resources

Search concepts

Search for a command to run...