This page describes my design and implementation of dark mode for this site, along with an interactive color editor.
Dark mode is an accessibility feature, along with an aesthetic choice. Both themes, dark and light, can cause eye strain under the wrong lighting conditions, so friendly sites provide an option.
Dark mode is gaining traction. iPhone will support dark mode in iOS 13, expanding on Apple’s 2018 introduction of system-wide Dark Mode for macOS. Many designers will follow Apple’s push. Dark mode is especially popular for conserving power on OLED displays.
I set out to create light and dark color palettes for this site.
- Theme agnostic design: style components without duplicating work for both themes.
- Find contrasting shades, so text is always legible.
- Generate both themes from a base palette, so colors are consistent, and easily adjustable.
- Follow user preference between light and dark themes. Match system theme where available.
Theme Agnostic Design
When a component looks right in one theme, it should automatically work in the other theme.
I decided on a mirrored color system to support both themes. Each color has shades of background and foreground, instead of light and dark:
The opposite theme has the same shades, in reversed order:
With a mirrored color system, switching between light and dark themes simply flips the foreground and background shades. I learned this technique from Pete Woodhouse’s Medium article on UI colour systems.
Here are some example styles using these shades:
Button state themes:
Sample buttons (try toggling dark mode, too):
I want to input arbitrary colors, and adjust until everything looks good. My theme generator takes these base colors as a hint, and finds shades with sufficient contrast.
It generates shades with three strength levels:
- Level 1 are the strongest shades, as close to base color as possible. Both modes use them (flippped from each other) as background 1 and foreground 1. The main text color (white or black) should be very clear on any background, so all level 1 shades should contrast well against their opposite pure color.
- Level 2 shades should stand out from all opposite level 1 shades. I never plan to put any foreground 1 against background 1. I want a weaker shade, foreground 2, which can be used against background 1 of any color. This also means foreground 1 can be used against background 2.
- Level 3 is even weaker than level 2.
The strictest accessibility standards require a contrast ratio of at least 7:1. Level 1 uses a contrast ratio of 9:1, and level 2 uses 7.1:1.
Computed Shade Palette
This tool generates background and foreground shades from a base palette, creating a mirrored color system.
Pick new base colors, or change the contrast requirements.
Following User Preference
To apply the current theme across all components, I use CSS custom properties:
First, search all loaded CSS rules to find each theme:
Next, reverse themes when the button is clicked:
The user’s preference should persist across pages.
This site uses
localStorage to save dark mode preference; your preference is never sent to a server.
Unfortunately, pages may initially load with the incorrect theme
I might be able to solve this with a
localStorage is unavailable in Workers).