# Website colour schemes: choosing colours for a site

[Canonical HTML page](https://gradiently.design/guide/website-color-scheme)

A site needs fewer colours than you think, and each one needs a job. Give them roles, check them against each other, and the whole site stays consistent as it grows.

## The short version

- A website colour scheme works best as a short list of roles: page ground, surface, text, muted text, border, accent and status colours.
- Most sites need one brand accent, used mainly for buttons and links, with neutrals doing the rest of the work.
- WCAG asks for a contrast ratio of at least 4.5:1 for normal text and 3:1 for large text and interface parts such as input borders.
- Storing colours as CSS custom properties, or design tokens, lets a whole site change theme by swapping one set of values.
- A dark theme is a separate set of values for the same roles, not an inversion of the light one.

A good **website color scheme** is not a mood board of five favourite colours. It is a short list of roles, each filled by one colour: the page ground, raised surfaces, body text, quieter text, borders, one accent for actions, and red, amber and green for status. Choose your brand accent first, build calm neutrals around it, check every text pairing for contrast, then store the result as CSS variables so the whole site uses the same values.

## The roles every site needs

| Role | Used for | Rule of thumb |
| --- | --- | --- |
| Ground | The page background | Slightly tinted rather than pure white or black feels softer |
| Surface | Cards, panels, menus | One step lighter (light theme) or lighter still (dark theme) than the ground |
| Text | Headings and body copy | Very high contrast against ground and surface |
| Muted text | Captions, labels, metadata | Still at least 4.5:1 against the ground |
| Border | Dividers and input outlines | Decorative dividers can be faint; input borders need 3:1 |
| Accent | Buttons, links, selected states | Your brand colour, used sparingly so it means "act here" |
| Status | Errors, warnings, success | Red, amber, green, tuned to sit with your accent |

Seven roles cover most sites. Name colours by role, not by hue, so changing the brand colour later is one edit.

## How to choose website colours

1. **Start with one accent** Your brand colour, or the one you want people to associate with you. If you don't have one, [how to choose brand colours](https://gradiently.design/guide/how-to-choose-brand-colors) helps.
2. **Tint the neutrals towards it** Greys with a hint of the accent's hue feel related to it. A teal brand gets cool, slightly blue greys; a terracotta brand gets warm, creamy ones.
3. **Decide light, dark or both** Pick the theme most visitors will see first and design it fully before starting the other.
4. **Check every text pairing** Text on ground, text on surface, muted text on both, white on the accent button. Fix anything under 4.5:1.
5. **Apply 60, 30, 10** Roughly 60% ground, 30% surfaces and text, 10% accent. The [60 30 10 rule](https://gradiently.design/guide/60-30-10-rule) explains the balance.

## Three website color palettes to start from

- Ground: #f7f9fb
- Surface: #ffffff
- Text: #14202b
- Muted text: #52606d
- Input border: #8a96a3
- Teal accent: #0f766e

Calm clinic, light. Text on ground is about 15.7:1, muted text 6.1:1, white on the teal button 5.5:1, and the input border just reaches 3:1 on white.

- Cream ground: #fbf6ef
- Oat surface: #efe4d6
- Espresso text: #2a1f17
- Muted text: #635e68
- Terracotta accent: #b4441c

Warm café, light. Espresso on cream is about 15:1; white on terracotta about 5.5:1, so button labels stay readable.

- Night ground: #0f0e17
- Raised surface: #1a1926
- Text: #ecebf3
- Muted text: #a5a3b8
- Lilac accent: #a78bfa

Night studio, dark. Off white text rather than pure white reduces glare; the lilac accent is about 7:1 on the ground, so use dark text on lilac buttons.

## Contrast rules that keep a site readable

The [WCAG contrast guidelines](https://www.w3.org/WAI/WCAG22/Understanding/contrast-minimum.html) set the floor: 4.5:1 for normal text, 3:1 for large text (about 24 px, or 19 px bold) and 3:1 for interface components such as input borders and icons that carry meaning. [WebAIM's contrast checker](https://webaim.org/resources/contrastchecker/) tests any pair. Our [colour contrast guide](https://gradiently.design/guide/color-contrast-accessibility) covers the reasons and the edge cases.

### Common failures

- Light grey placeholder text used as the only label
- White text on a pale brand colour such as yellow or sky blue
- Links that differ from body text by colour alone
- A pale border as the only outline of a form field
- Error messages shown only in red

### Fixes

- Real labels above fields, muted text at 4.5:1
- Dark text on light accents, or a deeper shade of the accent
- Underline links in body copy, or make them bold
- Input borders at 3:1 against their background
- An icon or words alongside the colour

## Coding your colour scheme as tokens

Store each role once as a CSS custom property and use only those variables in your styles. Then a dark theme, a seasonal campaign or a rebrand is a change to one block of values, not a search through every file. This is the core idea of [design tokens](https://gradiently.design/guide/design-tokens).

```css
:root {
  --ground: #f7f9fb;
  --surface: #ffffff;
  --text: #14202b;
  --text-muted: #52606d;
  --border-input: #8a96a3;
  --accent: #0f766e;
  --on-accent: #ffffff;
}

@media (prefers-color-scheme: dark) {
  :root {
    --ground: #0f0e17;
    --surface: #1a1926;
    --text: #ecebf3;
    --text-muted: #a5a3b8;
    --border-input: #6e6b85;
    --accent: #a78bfa;
    --on-accent: #0f0e17;
  }
}

body { background: var(--ground); color: var(--text); }
.card { background: var(--surface); }
.button { background: var(--accent); color: var(--on-accent); }
```

Roles, not hues. Note `--on-accent` flips from white to near black, because a light lilac button needs dark text.

## Dark mode is its own scheme

Inverting a light palette rarely works. Saturated accents glow too hard on black, shadows disappear, and pure white text causes glare. Build dark mode as a second set of values: a near black ground with a hint of hue, surfaces that get lighter as they rise, softer text, and an accent lightened until it reaches contrast. [Dark mode design](https://gradiently.design/guide/dark-mode-design) goes deeper.

## Where brand colour goes beyond buttons

If the accent is used only on buttons, the site can feel generic. The answer is not more accent everywhere but one place where the brand gets to be expressive: the hero, a feature band or the footer. A rich gradient in the brand's family works well there, while the rest of the page stays calm and readable.

A wide website hero for a physiotherapy clinic with a short headline on a rich gradient

One expressive band at 1920×1080 carries the brand; the rest of the site uses the calm roles above.

A Gradiently Mark can be that expressive layer: a background nobody else has, which picks a type colour from its own palette for each line so headings stay readable. For more on pairings, see [colour harmony](https://gradiently.design/guide/color-harmony) and [hero section design](https://gradiently.design/guide/hero-section-design).

## FAQ

### How many colours should a website have?

Usually one brand accent, three to five neutrals for ground, surfaces, text and borders, and three status colours. More than one accent makes it harder to tell what is clickable.

### How do I choose a colour scheme for my website?

Start with your brand accent, tint neutral greys towards its hue, decide on a light or dark theme, and check every text pairing for at least 4.5:1 contrast.

### What contrast ratio does website text need?

WCAG asks for at least 4.5:1 for normal text and 3:1 for large text and interface parts such as input borders.

### Should a website background be pure white?

It doesn't have to be. A very slightly tinted off white often feels calmer and lets white cards stand out as surfaces.

### How do I add dark mode to my colour scheme?

Define each colour role as a CSS custom property, then provide a second set of values inside a `prefers-color-scheme: dark` media query.
