Color & Contrast
Color Harmony Rules
OKLCH-based color harmony strategies for consistent, accessible palettes in light and dark mode.
How To Use This Guide
Use this while choosing patterns, tones, or tools. It is best as lookup material, not as a first read.
At A Glance
- Level
- intermediate
- Type
- Reference
- Updated
- 2026-03-22
Why OKLCH?
OKLCH is perceptually uniform — rotating the hue wheel keeps consistent visual brightness and saturation. HSL doesn’t: hsl(60, 100%, 50%) (yellow) looks much brighter than hsl(240, 100%, 50%) (blue).
OKLCH: oklch(lightness% chroma hue)
- Lightness: 0% (black) → 100% (white)
- Chroma: 0 (gray) → 0.4 (max saturation)
- Hue: 0-360 (color wheel)
Harmony Strategies
Monochromatic (safest)
One hue, vary lightness and chroma. Always works.
:root {
--mono-50: oklch(97% 0.02 250);
--mono-100: oklch(93% 0.04 250);
--mono-200: oklch(85% 0.06 250);
--mono-500: oklch(55% 0.18 250); /* primary */
--mono-700: oklch(40% 0.16 250);
--mono-900: oklch(25% 0.10 250);
}
Complementary (high contrast)
Two hues 180° apart. Use one as accent, the other as primary.
:root {
--primary: oklch(55% 0.18 250); /* blue */
--complement: oklch(55% 0.18 70); /* warm amber — 250 + 180 = 430 → 70 */
}
Analogous (harmonious)
Three hues within 30° of each other. Feels cohesive and natural.
:root {
--color-a: oklch(55% 0.16 220); /* teal */
--color-b: oklch(55% 0.18 250); /* blue — center */
--color-c: oklch(55% 0.16 280); /* purple */
}
Split-Complementary (balanced contrast)
Primary + two colors adjacent to its complement. Easier than full complementary.
:root {
--primary: oklch(55% 0.18 250); /* blue */
--split-a: oklch(55% 0.14 40); /* 250+180-30 = orange-ish */
--split-b: oklch(55% 0.14 100); /* 250+180+30 = yellow-green */
}
The 60-30-10 Rule
60% — Neutral base (bg, surfaces) → gray/off-white
30% — Secondary (cards, sections) → tinted neutrals or light accent
10% — Accent (CTAs, links, badges) → your primary color at full chroma
System Prompt for Color Palette Generation
Generate a color palette using OKLCH color space for a Tailwind CSS website.
Rules:
1. Define exactly 6 shades (50, 100, 200, 500, 700, 900) per color.
2. Keep lightness consistent across different hues at the same shade level.
3. Chroma scale: 50-200 use low chroma (0.01-0.06), 500 uses peak (0.14-0.22), 700-900 reduce slightly.
4. Dark mode: reduce chroma by 15%, increase lightness of accent shades by 10%.
5. Neutral palette: use hue from primary at chroma < 0.01 for warm/cool grays.
6. Test: primary-500 on white must have 4.5:1 contrast. Primary-500 on gray-900 must have 4.5:1.
7. Output format: CSS custom properties with oklch() values.
Harmony type: [monochromatic / complementary / analogous / split-complementary]
Primary hue: [0-360]
Mood: [warm / cool / neutral / vibrant / muted]
Quick Palette Formula
Given a primary hue H:
| Token | Formula | Use |
|-------|---------|-----|
| --color-50 | oklch(97% 0.02 H) | Tinted backgrounds |
| --color-100 | oklch(93% 0.04 H) | Hover states |
| --color-200 | oklch(85% 0.06 H) | Borders, subtle fills |
| --color-500 | oklch(55% 0.18 H) | Primary buttons, links |
| --color-700 | oklch(40% 0.16 H) | Active states |
| --color-900 | oklch(25% 0.10 H) | Dark text on light bg |
Checklist
- [ ] All colors defined in OKLCH
- [ ] One primary hue chosen, harmony strategy documented
- [ ] 60-30-10 ratio applied across layout
- [ ] Neutral grays tinted with primary hue (chroma < 0.01)
- [ ] Dark mode chroma reduced by 10-15%
- [ ] WCAG AA contrast verified (4.5:1 body, 3:1 large text)
- [ ] Accent color tested on both light and dark surfaces
- [ ] No more than 3 distinct hues in the palette