Color Palette Guide: Theory to Professional UI Palettes
Color Theory Fundamentals
The HSL Color Model
H (Hue): 0-360°, the angle on the color wheel
S (Saturation): 0-100%, gray → pure color
L (Lightness): 0-100%, black → white
| Hue value | Color |
|---|---|
| 0° / 360° | Red |
| 60° | Yellow |
| 120° | Green |
| 180° | Cyan |
| 240° | Blue |
| 300° | Magenta |
The Color Wheel
0° Red
300° 60°
Magenta Yellow
240° 120°
Blue Green
180° Cyan
Five Classic Color Schemes
1. Monochromatic
One hue with varying saturation and lightness.
:root {
--primary-50: hsl(220, 100%, 97%); /* Lightest blue */
--primary-100: hsl(220, 100%, 94%);
--primary-200: hsl(220, 100%, 88%);
--primary-300: hsl(220, 100%, 78%);
--primary-400: hsl(220, 100%, 68%);
--primary-500: hsl(220, 100%, 58%); /* Base blue */
--primary-600: hsl(220, 100%, 48%);
--primary-700: hsl(220, 100%, 38%);
--primary-800: hsl(220, 100%, 28%);
--primary-900: hsl(220, 100%, 18%); /* Darkest blue */
}
Best for: Clean, professional, strong brand identity
2. Analogous
Colors 30° apart on the color wheel.
:root {
--analogous-1: hsl(200, 80%, 50%); /* Blue */
--analogous-2: hsl(220, 80%, 50%); /* Blue-violet */
--analogous-3: hsl(240, 80%, 50%); /* Violet */
}
Best for: Harmonious, natural, warm
3. Complementary
Colors 180° apart on the color wheel.
:root {
--primary: hsl(220, 80%, 55%); /* Blue */
--complement: hsl(40, 80%, 55%); /* Orange */
}
Best for: High contrast, eye-catching, CTA buttons
4. Triadic
Three colors evenly spaced 120° apart on the color wheel.
:root {
--triadic-1: hsl(0, 70%, 55%); /* Red */
--triadic-2: hsl(120, 70%, 55%); /* Green */
--triadic-3: hsl(240, 70%, 55%); /* Blue */
}
Best for: Vibrant, colorful, children's products
5. Split-Complementary
The two colors 30° on either side of the complement.
:root {
--primary: hsl(220, 80%, 55%); /* Blue */
--split-1: hsl(10, 80%, 55%); /* Red-orange */
--split-2: hsl(50, 80%, 55%); /* Yellow-orange */
}
Best for: Rich without being chaotic; softer than complementary
WCAG Contrast Standards
Calculating Contrast
Contrast ratio = (L1 + 0.05) / (L2 + 0.05)
L1 = relative luminance of the lighter color
L2 = relative luminance of the darker color
Relative luminance:
L = 0.2126 × R + 0.7152 × G + 0.0722 × B
(R/G/B must be linearized from sRGB first)
WCAG 2.1 Standards
| Level | Body text | Large text | UI components |
|---|---|---|---|
| AA | 4.5:1 | 3:1 | 3:1 |
| AAA | 7:1 | 4.5:1 | - |
Large text: ≥18pt (24px) or ≥14pt bold
Checking Contrast with JavaScript
function getContrastRatio(color1: string, color2: string): number {
const l1 = getRelativeLuminance(color1);
const l2 = getRelativeLuminance(color2);
const lighter = Math.max(l1, l2);
const darker = Math.min(l1, l2);
return (lighter + 0.05) / (darker + 0.05);
}
function getRelativeLuminance(hex: string): number {
const rgb = hexToRgb(hex);
const [r, g, b] = [rgb.r / 255, rgb.g / 255, rgb.b / 255]
.map(c => c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4));
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
}
function meetsWcagAA(fg: string, bg: string, isLargeText = false): boolean {
const ratio = getContrastRatio(fg, bg);
return isLargeText ? ratio >= 3 : ratio >= 4.5;
}
Generating Professional Palettes
Tailwind CSS-Style Color Steps
function generatePalette(baseHue: number, baseSat: number) {
const lightnesses = [97, 94, 88, 78, 68, 58, 48, 38, 28, 18];
return lightnesses.map((l, i) => ({
name: `${(i) * 100}`,
value: `hsl(${baseHue}, ${baseSat}%, ${l}%)`,
}));
}
// Generate a blue palette
const bluePalette = generatePalette(220, 80);
// 50: hsl(220, 80%, 97%)
// 100: hsl(220, 80%, 94%)
// ...
// 900: hsl(220, 80%, 18%)
The OKLCH Color Space (More Uniform)
/* OKLCH is more perceptually uniform than HSL */
:root {
--blue-50: oklch(97% 0.01 250);
--blue-500: oklch(62% 0.19 250);
--blue-900: oklch(30% 0.12 250);
}
| Color space | Perceptual uniformity | Browser support |
|---|---|---|
| HSL | ❌ Not uniform | All |
| OKLCH | ✅ Uniform | Chrome 111+, Safari 15.4+ |
| OKLAB | ✅ Uniform | Chrome 111+, Safari 15.4+ |
Dark Mode Palettes
/* Light */
:root {
--bg: #ffffff;
--surface: #f5f5f5;
--text: #1f2937;
--text-secondary: #6b7280;
--border: #e5e7eb;
}
/* Dark: don't simply invert — reduce contrast instead */
[data-theme="dark"] {
--bg: #111827;
--surface: #1f2937;
--text: #f9fafb;
--text-secondary: #9ca3af;
--border: #374151;
}
Dark Mode Palette Principles
- Don't use pure black
#000: Use dark grays like#111827 - Lower the saturation of primary colors: High saturation is harsh in dark mode
- Keep contrast ≥ 4.5:1: WCAG AA standard
- Replace shadows with darker surface layers: Shadows are invisible in dark mode
Classic Palette References
Tech / SaaS
Primary: #3b82f6 (blue 500)
Secondary: #8b5cf6 (violet 500)
Accent: #06b6d4 (cyan 500)
Background: #f8fafc
Text: #0f172a
E-commerce / Consumer
Primary: #f97316 (orange 500)
Secondary: #ef4444 (red 500)
Accent: #22c55e (green 500)
Background: #ffffff
Text: #1f2937
Finance / Professional
Primary: #1e40af (blue 800)
Secondary: #059669 (green 600)
Accent: #d97706 (amber 600)
Background: #f9fafb
Text: #111827
Generating Palettes with ToolsKu
- Open the Color Converter or the Gradient Generator
- Pick a base color
- Automatically generate color steps (50-900)
- Check whether the contrast meets WCAG AA
- Preview the dark mode effect
- Copy the CSS variable code
FAQ
Why does my palette look "muddy"?
In HSL, perceived saturation is inconsistent at high and low lightness levels. Use the OKLCH color space to generate cleaner color steps.
Colors too harsh in dark mode?
Lower saturation by 20-30% and raise lightness by 5-10%:
/* Light */
--primary: hsl(220, 80%, 55%);
/* Dark: reduced saturation */
--primary: hsl(220, 60%, 65%);
How do I make sure my palette is color-blind friendly?
- Don't rely on color alone to convey information (add icons/text)
- Red-green combinations are unfriendly to color-blind users; use blue-orange instead
- Test with a color blindness simulator
Summary
Good palettes come from color theory + contrast standards + real testing. Master the five classic color schemes, WCAG contrast standards, and the OKLCH color space, and you can generate professional-grade palettes. Remember: color schemes are not art — they are engineering. There are standards to follow and tools to measure with.