Design Principle
A color scale is not a hex color linearly tinted and shaded. Healthy theme scales control perceived lightness, saturation, brand tone, and usage semantics together.
Large Theory
HSL, RGB, or simple hex tint/shade often produce uneven perceived brightness, hue drift, and neon dark-mode palettes. OKLCH expresses color through lightness, chroma, and hue, which makes it more suitable for programmatic scales, saturation control, and light/dark themes. OKLCH is not automatically accessible: output still needs semantic tokens and foreground/background pair checks.
Small Points
- Lightness controls perceived brightness and helps create the ladder from background to body text.
- Chroma controls color intensity; dark mode, highlighted states, and large surfaces often need lower chroma.
- Hue angles cannot be copied mechanically from HSL because hue positions differ across color spaces.
- Generate candidate steps first, then compress them into roles such as bg, surface, border, text, muted, accent, focus, danger, and success.
- Wide-gamut and high-chroma colors may fall outside sRGB and need gamut mapping or fallback.
- Color tokens need usable surfaces, forbidden pairs, contrast targets, and dark-mode counterparts, not just single values.
Design Judgment
A scale can enter the design system when adjacent steps progress predictably, body/muted/border tokens remain clear on their surfaces, accent colors do not pollute content areas, and dark mode avoids neon noise. Twelve attractive swatches are not yet a usable token system.
Implementation Notes
Use Color.js or Culori to convert seed colors into OKLCH, generate 9-12 candidate steps, then select semantic roles. Export oklch() values, sRGB/hex fallbacks, light/dark mappings, pair contrast matrix, component examples, and forbidden combinations. In CSS, write fallbacks first and then override modern color with @supports (color: oklch(0% 0 0)).
Counterexamples/Risks
Generating every state with HSL lighten(), using a high-chroma brand color for small body text, making dark mode by only inverting lightness, exposing every OKLCH step to components, and omitting non-color redundancy for charts, status, or focus.
Case Study
Radix Colors connects a 12-step palette to backgrounds, interactive components, borders, solid colors, and accessible text. Material Theme Builder translates dynamic color into light/dark roles and supports code export. The reusable lesson is that modern color tools matter because they compress scales into executable roles, not because they create attractive swatches.
Source Links
W3C CSS Color Module Level 4: https://www.w3.org/TR/css-color-4/ MDN oklch(): https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/color_value/oklch Radix Colors: https://www.radix-ui.com/colors Material Theme Builder: https://m3.material.io/theme-builder/ Color.js: https://colorjs.io/ Culori: https://culorijs.org/
Agent Directive
When generating theme colors, use OKLCH or another perceptual color space to create candidate steps, then map them to semantic tokens, fallbacks, and a pair matrix; do not output purposeless swatches.