Light and Dark Website Color Palettes: A Practical Guide
A useful dark theme keeps the same jobs for its colors while changing their brightness. Start with a background, readable text, a primary action, a supporting surface, and an accent.
1. Keep the roles consistent
Use surface for the page, ink for text, primary for links and buttons, secondary for cards, and accent for a small highlight. These names let components follow either theme without rewriting every style.
2. Try these two matching palettes
Light theme
Clear text, a calm surface, and one obvious next step.
Open this paletteDark theme
Clear text, a calm surface, and one obvious next step.
Open this palette| Role | Light | Dark |
|---|---|---|
| surface | #F8FAFC | #101827 |
| ink | #172033 | #E2E8F0 |
| primary | #1D4ED8 | #93C5FD |
| secondary | #E2E8F0 | #1E293B |
| accent | #9A3412 | #FDBA74 |
The dark theme uses a brighter blue and orange so they remain readable against dark surfaces. It also uses a slightly lighter card background to show hierarchy. Avoid simply inverting every hex value.
3. Test the actual foreground and background
For normal text, WCAG AA requires at least 4.5:1; large text needs 3:1. Large means at least 24 CSS pixels, or about 18.7 pixels when bold. Compare the unrounded result. See W3C’s contrast explanation.
These examples use white button text in light mode and dark button text in dark mode. Recheck text on cards, links, hover states, focus indicators, and any new accent background in the contrast checker. A passing palette does not establish accessibility for the whole website.
4. Apply the roles with CSS
:root {
--surface: #F8FAFC;
--ink: #172033;
--primary: #1D4ED8;
--secondary: #E2E8F0;
--accent: #9A3412;
--on-primary: #FFFFFF;
}
@media (prefers-color-scheme: dark) {
:root {
--surface: #101827;
--ink: #E2E8F0;
--primary: #93C5FD;
--secondary: #1E293B;
--accent: #FDBA74;
--on-primary: #101827;
}
}
body { background: var(--surface); color: var(--ink); }
.card { background: var(--secondary); }
.button { background: var(--primary); color: var(--on-primary); }
a { color: var(--primary); text-decoration: underline; }
This follows the visitor’s system preference. If you add a manual theme switch, let its explicit choice override the media query and remember it locally. Check form controls, disabled states, and images in both modes; the color variables alone do not restyle them.
5. Adjust, check, and export
- Open one of the example palettes above in HueWiz.
- Edit a role and inspect the preview and contrast checks.
- Use Copy code or Download to export the palette. Each export represents the current theme; keep both sets in your theme stylesheet.
- Copy a share link to preserve all five roles for review.