How to choose website colors: give every color a job
Start with what a color needs to do. A beautiful row of swatches becomes a useful website palette when you know which one is the page, the text, and the action.
Reviewed 7 October 2026 · 3 min read

An original AI-generated paper color study. The working palette uses the exact hex values below.
Start with one real screen
Pick a screen that contains the things your site actually needs: a heading, a paragraph, a link, a primary action, and a secondary panel. A palette that works on a logo may need different roles on a page full of text. Testing a realistic screen makes those needs visible early.
Choose a palette for its visual character, then treat its roles as a proposal. You can keep a favorite bright color without making it the body text or putting white labels on top of it.
Assign five simple roles
| Role | Color | Job |
|---|---|---|
| Background | #F5F6F0 | The main canvas |
| Surface | #E7EAD9 | Secondary panels and cards |
| Text | #20241D | Headings and body copy |
| Primary | #3448C5 | The main action and text links |
| Accent | #D5EC59 | Highlights and supporting fills |
These are starting roles, not a complete design system. A form-heavy application may also need distinct error, success, warning, focus, and border tokens. Add them when the interface needs them, and test the actual combinations.
Check the pairs that will touch
In this example, text on the page background has 14.51:1 contrast. The primary blue on that same background has 6.71:1. Both meet the AA normal-text threshold of 4.5:1. The yellow-green accent on the background is only 1.21:1, so it should not carry small text there.
Put the accent behind a dark label instead: black on the yellow-green fill has 15.97:1. That lets you retain the character of the palette while giving the words a readable pairing. The standard applies to the foreground and background together, not to an isolated hex code. W3C explains the text contrast thresholds.
Make hierarchy with more than color
Use spacing, size, weight, position, and labels to make the reading order clear. A primary action can have a filled background and a clear verb. A secondary link can remain underlined. An error needs an explanation, not just a red outline.
A pale surface may look different enough for decorative grouping but still be insufficient as the sole visible boundary of a required control. Check essential component boundaries against their adjacent colors. W3C’s non-text contrast guidance describes the relevant 3:1 requirement and exceptions.
Name tokens for their purpose
Use --color-primary instead of --blue when the variable describes an action role. If the brand later changes, the name still makes sense. Give text on a colored fill its own token, such as --color-on-primary; it does not have to match the body text.
Our studio expands those starting roles into two independent themes with 12 named roles each, including links, secondary text, borders, focus rings, hover fills and black or white labels. Copy those tokens into your stylesheet, then check them on your actual components. Exporting colors does not automatically update existing CSS or audit a finished site.
A useful final pass
- Read a real paragraph at its intended size, including on the secondary surface.
- Check links, button labels, form boundaries, and focus indicators.
- Inspect hover, selected, error, and disabled states in their actual context.
- Use labels, shapes, or patterns wherever color communicates a difference.
- Review the page on a narrow screen and with enlarged text.
Keep the result focused: fewer intentional roles are easier to maintain than many nearly identical shades with no clear purpose.
Try the worked example
See Cobalt & citrus on a live interface, change any role, and check every pair.
Open Cobalt & citrus ↗Our examples use original palette values and the WCAG 2.2 calculation. Full methodology and primary sources.
← All field notes