YUKRONCREATIVE
← All guides

Colour Systems Without Guesswork

UI/UX · ~8 min read

Most colour chaos comes from choosing colours one at a time, in isolation, by eye. You pick a nice blue for a button, then invent a slightly different blue for a link, then a third for a hover state, and within a month nobody can tell you which blue is correct. A colour system replaces that guessing with a repeatable method.

Choose your ramps, not your colours

The unit of a colour system is the ramp: a family of related shades of a single hue, from very light to very dark. You build a handful of ramps — primary, neutral, success, warning, danger — and then compose interfaces from them. Consistency becomes structural rather than a matter of willpower.

A useful ramp has around nine to eleven steps. Ten is a common and tidy number: 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, where 50 is a near-white tint and 900 is a near-black shade. The midpoints — 400 to 600 — are where interactive colour lives; the extremes are for backgrounds and text.

Generate in a perceptual space

Naive ramps are made by mixing a hue with white and black in a linear colour space, and they betray you: the light tints go muddy or pastel-grey, and the dark shades lose saturation and turn to mud. The fix is to generate ramps in a perceptual colour model such as OKLCH, where lightness is a separate, roughly even axis.

The practical recipe for each step:

Because lightness is explicit, you can now reason about contrast instead of testing colours one pair at a time after the fact.

If two steps in a ramp look identical when viewed in greyscale, they are too close to serve different roles. Contrast, not hue, is what carries most information on a screen.

Two layers: primitives and semantics

A colour system has two layers, and mixing them is the most common source of pain.

Components should only ever ask for a semantic token. That way, changing the brand from blue to green is a single edit in the mapping layer, and dark mode is a second column of mappings rather than a redesign.

Semantic roleLight modeDark modeTypical use
surface-defaultgrey-50grey-900Page background
surface-raisedwhitegrey-800Cards, menus
text-primarygrey-900grey-50Body copy
text-secondarygrey-600grey-300Supporting labels
border-defaultgrey-200grey-700Dividers, inputs
action-primaryblue-600blue-400Primary buttons
feedback-dangerred-600red-400Errors, destructive actions

Contrast targets, not vibes

Accessibility is the constraint that keeps a colour system honest. The WCAG ratios you should design against:

The subtle one is that third rule. A pale-grey input border on a white card can look elegant and still fail, because the border is the thing that communicates the control exists. Check component boundaries, not just text.

Colour is never the only signal

Around one in twelve men has some form of colour-vision deficiency, so a system that says "green means success, red means error" and nothing else fails a large chunk of users. Pair every colour cue with a second channel:

Design the greyscale version first. If the meaning survives without hue, the colour you add afterwards is enhancement rather than the entire message.

Surfaces, elevation and dark mode

Depth in flat interfaces comes from surface colour, not shadows alone. Define a small ladder of surface levels — default, raised, overlay — and step them apart slightly. In dark mode the ladder inverts in logic: further-forward surfaces get lighter, not darker, because a shadow on a dark background is nearly invisible. Reduce pure-white-on-black contrast too; a soft off-white on a dark-grey surface is easier on the eye than maximum contrast, which can smear and halate for some readers.

Practice: building a status set

A quick exercise shows the whole method working. Say you need four feedback states. You already have ramps, so you do not invent colours — you assign roles:

  1. Pick the 600 step of each hue for the icon and text in light mode, and the 400 step for dark mode.
  2. Pair each with a tinted background from the 50–100 range (light) or the 800–900 range (dark), not a pure white or pure black, so the state reads as a distinct surface.
  3. Check every foreground-on-background pair against 4.5:1 for text and 3:1 for the icon.
  4. Give each state a distinct icon and a short label, so colour is never the only signal.

Four states, one consistent recipe, no hand-picked colours. Repeat the pattern for informational, success, warning, danger and neutral states and the whole product speaks one visual language, whether the message appears in a toast, a banner or an inline field error.

Document, then guard the system

A colour system only works if it is enforced. Keep the ramps and mappings in one version-controlled file, expose them as tokens, and add an automated contrast check to your build so a failing pair fails the pipeline rather than reaching users. Review new colour requests against the semantic layer first: nine times out of ten, the colour someone "needs" already exists as a role they had not noticed.

Key takeaways

  • Build ramps of nine to eleven steps per hue, not one-off colours; compose the interface from ramps.
  • Generate ramps in a perceptual space such as OKLCH so lightness is even and tints and shades stay clean.
  • Keep two layers — primitive ramps and semantic roles — and let components reference only the semantic layer.
  • Design to WCAG ratios: 4.5:1 for body text, 3:1 for large text and for meaningful component boundaries.
  • Never rely on colour alone; pair every colour cue with an icon, shape or label, and check in greyscale.
  • Handle dark mode by inverting the surface ladder's logic, and enforce the system with tokens and automated contrast checks.