Opens in a new tab

How to Build a Colour System From One Brand Colour

One base (500) → a full ramp of tints and shades50100200300400500600700800900base
A perceptual tint/shade ramp is the backbone of a UI palette.

Intermediate · Studio Colour

Knowing colour theory is one thing; turning a single brand colour into a working UI palette is another. This is the intermediate step between “I have a nice purple” and “every button, border, surface and state has a defined, accessible colour.” We’ll build a full ramp from one base, tint the neutrals, add semantic colours, wire it to tokens, and make dark mode fall out for free.

From one colour to a scale

Start with your base at the middle of a 50–900 scale (500). Build lighter tints above it and darker shades below. The trick most people miss: step by perceived lightness, not by evenly adding white and black — otherwise the light end bunches up and the dark end falls off a cliff.

The clean way to do this is in OKLCH, where the L channel is perceived lightness. Keep hue and chroma roughly constant and walk L in even steps:

/* Even perceived steps: only L changes */
--p-50:  oklch(0.97 0.03 285);
--p-500: oklch(0.55 0.20 285);   /* your base */
--p-900: oklch(0.25 0.10 285);

Notice chroma tapers at the extremes — very light and very dark colours can’t hold as much saturation, so easing it off keeps the ramp believable.

Don’t forget the neutrals

A brand ramp alone can’t build a UI — you need greys for text, surfaces and borders. But pure grey next to a saturated brand looks dirty. Tint your neutrals with a whisper of the brand hue (chroma ~0.01–0.03) so they feel related:

--n-100: oklch(0.96 0.005 285);   /* barely purple grey */
--n-700: oklch(0.40 0.015 285);

Assign roles, not just values

A palette becomes a system when each step has a job: 50–100 for backgrounds and hovers, 200–300 for borders and dividers, 500 for primary actions, 600–700 for hover/active states, 800–900 for text on light. Name them by role so swapping the brand colour later re-themes everything:

--surface:    var(--n-50);
--border:     var(--p-200);
--primary:    var(--p-500);
--primary-hv: var(--p-600);
--text:       var(--n-900);

Components reference the role tokens, never the raw ramp. That one layer of indirection is what makes a re-theme a five-minute job instead of a find-and-replace across the codebase.

Add semantic colours

Success, warning, and danger aren’t decoration — they carry meaning, so they need their own small ramps (green, amber, red) built the same perceptual way. Match their L at each step to the brand ramp so a green button and a purple button feel like the same weight.

Apply the 60-30-10 rule

Dominant/neutral 60%, secondary 30%, accent 10%. Your scale supplies all three: a near-neutral for the 60, a mid tone for the 30, and the saturated 500 as the 10% accent that draws the eye to actions. If everything is branded, nothing stands out — the discipline is what makes the accent read as “click here.”

Dark mode for free

Because the ramp is defined by perceived lightness, dark mode is mostly a matter of flipping which end you pull from. Surfaces move to 900–800, text to 100–200, and the primary often shifts up a step or two so it stays vivid on a dark surface. Redefine the role tokens inside a prefers-color-scheme block and every component follows — no per-component overrides.

Check every pair for contrast

A system is only usable if the text-on-surface pairings pass. 700–900 on 50–100 is safe; 400 on white almost never is. Lock the accessible pairings before you ship the tokens — aim for WCAG 4.5:1 on body text and 3:1 on large text and UI borders. Build the contrast check into the ramp, not as an afterthought, and you’ll never ship an unreadable state.

Common mistakes

  • Stepping by equal RGB amounts. The light end bunches and the dark end collapses. Step by perceived lightness instead.
  • Pure-grey neutrals. They look muddy beside a saturated brand. Tint them with a trace of the brand hue.
  • Hard-coding ramp values in components. Reference role tokens so a re-theme stays trivial.
  • Full chroma at the extremes. Very light and very dark steps can’t hold saturation — ease it off.
Build the ramp in one click

Studio Colour spins a single base into a perceptually even tint-and-shade scale, tints your neutrals, checks every pair for contrast, and exports the lot as tokens. Free Chrome side panel.

Try Studio Colour →

Illustrated portrait of Mark Carranza
Written by Mark Carranza
Founder, Studio Grid
Mark leads the design of every Studio Grid tool, from Studio Colour in the browser to Studio Convert on the Mac.

Related posts

Leave the first comment