Guide

How to create a website color palette

Most palette advice stops at picking three colours. That is the easy part and almost none of the work.

Last updated 25 August 2026

A palette of five swatches is not a colour system. What a site actually needs is a set of decisions about which colour goes where, in enough steps that every state has one, with the combinations checked. Getting from the first to the second is the job.

Start with the neutrals, not the brand colour

This is the part that surprises people. On a finished interface, somewhere between 85 and 95 percent of the pixels are neutral: backgrounds, borders, body text, dividers, disabled states, shadows. The brand colour is a small fraction of what anyone sees.

So the neutrals decide the character. A neutral ramp with a slight blue cast reads as cool and technical; a slight warm cast reads as approachable and editorial; a pure grey reads as neutral, which is itself a choice.

You need more neutral steps than feels reasonable, around eleven to thirteen. It sounds excessive until you count the jobs: page background, card background, sunken panel, subtle border, default border, strong border, disabled fill, disabled text, subtle text, muted text, body text, strong text, and inverse. Each is a different value, and each one you skip becomes a hardcoded one-off later.

Then one accent, used sparingly

Use one accent, not three. A single accent colour, used only for the primary action, is more legible than a palette where four things compete to look important, because when everything is emphasised, nothing is.

Pick it for contrast against your neutrals rather than for its own beauty in isolation. A colour that looks superb on a white swatch card can disappear against a light grey panel.

If you need a second colour, give it a different job rather than the same job in another hue: links and data, say, rather than "another kind of button". A second colour with its own purpose is a system; a second colour with the same purpose is a coin toss for whoever builds the next screen.

Add semantic colours, deliberately different

Success, warning and error need to be immediately recognisable, which means they should not be confusable with your accent. If your accent is orange and your warning is amber, every primary button looks like a caution.

Keep them conventional. Green for success, amber for warning, red for error is not imaginative, but it is what people already know, and this is not the place to be original.

And never let colour be the only signal. A red border with no icon and no message is invisible to a meaningful share of your users. See designing for colour blindness.

Building the ramps

For each colour you need several steps. There are two ways to build them, and one is better:

Mixing toward white and black is quick and gives predictable results for tints and shades. It is what the colour picker generates. The catch is that mixing in sRGB darkens unevenly and can shift hue.

Stepping lightness in OKLCH is better. Hold chroma and hue, walk lightness in even increments, and you get a ramp where each step looks like the same size step. In HSL the same numeric increments produce a ramp that lurches, because HSL lightness is not perceptual.

Either way, do not hand-pick each step by eye. Generate them, then adjust the two or three that look wrong. Hand-picked ramps drift.

Sampling a palette from an image

Pulling a palette out of a photograph is a genuinely good starting point, because the colours in a photograph already agree with each other: one light source produced them all.

Two things to watch. First, the proportions in the image are information: the palette generator reports what share of the image each colour covered, and a colour that was four percent of a photograph will not survive as a page background. Second, photographic colours are usually too saturated for interface chrome. Use them for accents and illustration; derive your neutrals separately.

Check the combinations, not the colours

This is where most palettes fail. A swatch sheet where every colour looks good tells you nothing about whether your body text is readable on your card background.

Write down the pairs you will actually ship, and check each one:

  • Body text on page background, and on card background
  • Muted text on both of those
  • Button label on button fill, in its default, hover and pressed states
  • Link colour on every surface it appears on
  • Border colours against their adjacent surfaces (3:1 if they carry meaning)
  • Focus ring against every background it can land on
  • Every one of those again in dark mode

The contrast checker gives the ratio and the WCAG verdict for each. Expect to adjust two or three values; that is normal, and it is much cheaper now than after the components are built.

Dark mode is aliases, not a second palette

Do not build two palettes. Build one ramp, then define the roles twice. Dark mode reassigns --surface-card from your lightest neutral to a dark one; it does not introduce new colours.

Two adjustments are usually needed. Saturated colours look more intense on dark backgrounds, so accents often want to step one or two levels lighter and slightly less saturated. And pure black backgrounds with pure white text are harsh, so pull both in from the extremes.

A workable order

  1. Choose a neutral temperature. Build eleven to thirteen steps.
  2. Choose one accent. Build a ramp for it.
  3. Add success, warning and error, distinct from the accent.
  4. Define role aliases (surfaces, text, borders, actions) that point at ramp steps.
  5. Redefine only the aliases for dark mode.
  6. Check every real pair for contrast. Adjust.
  7. Check the whole set in the vision simulator.
  8. Write it down as custom properties and stop picking colours.

That last step is the reason for the rest. A colour system exists so that the next person, including you in three months, does not have to make a colour decision at all.