Codeskill

Learn to code, step by step

Colour – relative colour, contrast, gamut

Advanced colour in CSS – relative colour syntax, contrast-aware choices, and wide-gamut displays. Hex codes copied from a brand PDF are a starting point, not a system.

Relative colour syntax

Derive variants from an existing colour without Sass:

:root {
  --brand: oklch(0.55 0.18 250);
  --brand-hover: oklch(from var(--brand) calc(l + 0.08) c h);
  --brand-muted: oklch(from var(--brand) l calc(c * 0.4) h);
  --brand-on: oklch(from var(--brand) 0.98 0.02 h);
}

Adjust lightness, chroma, or hue relative to a token. When brand blue changes, hover and muted variants update automatically. Prefer OKLCH or LCH for perceptually even steps – RGB math darkens blues differently from yellows.

colour-mix() for simple blends

:root {
  --surface: #ffffff;
  --text: #1a1a1a;
  --border: color-mix(in oklab, var(--text) 12%, var(--surface));
  --link: color-mix(in oklab, var(--brand) 85%, var(--text));
}

color-mix() is straightforward when you need a halfway point. Relative syntax wins when the adjustment is parametric (always 8% lighter).

Contrast and readability

WCAG contrast ratios still matter. Use color-contrast() where supported to pick a readable foreground from a list:

.badge {
  --bg: var(--brand);
  background: var(--bg);
  color: color-contrast(var(--bg) vs white, black);
}

Where color-contrast() is unavailable, define paired tokens upfront – --brand and --brand-fg – and audit with a contrast checker in CI or design review.

Wide gamut (P3)

sRGB hex cannot show every colour modern displays render. Declare vivid accents in Display P3 when it helps:

:root {
  --accent: #007aff; /* sRGB fallback */
  --accent: color(display-p3 0.12 0.45 1);
}

@supports (color: color(display-p3 1 1 1)) {
  .hero {
    background: linear-gradient(
      135deg,
      color(display-p3 0.2 0.5 1),
      color(display-p3 0.6 0.2 0.9)
    );
  }
}

Always provide an sRGB fallback first. Most users will not notice P3 gradients; brand-heavy marketing pages sometimes do.

Forced colours and colour-scheme

@media (forced-colors: active) {
  .btn {
    border: 2px solid ButtonText;
    background: ButtonFace;
    color: ButtonText;
  }
}

:root {
  color-scheme: light dark;
}

Windows high-contrast mode and similar settings override your palette. Use system colours where needed instead of fighting the OS. color-scheme hints native form controls and scrollbars toward light or dark.

Practical token shape

  • Store base colours as custom properties in OKLCH.
  • Derive hover, muted, and on-colour variants with relative syntax.
  • Document minimum contrast pairs in your design system.
  • Test dark mode tokens separately – relative adjustments from a light brand colour do not always land well on dark surfaces.

The next tutorial covers typography systems – scales for UI and long-form reading, variable fonts, and OpenType features.

PreviousAnchor positioning and popover styling