| tags |
|
|||
|---|---|---|---|---|
| type | system-doc |
Comprehensive guidelines for establishing HSL/OKLCH color tokens, semantic palettes, color accessibility, and automated dark mode generation.
:root {
/* Brand Tokens */
--brand-hue: 250;
--brand-saturation: 85%;
--brand-lightness: 60%;
--brand-primary: hsl(var(--brand-hue), var(--brand-saturation), var(--brand-lightness));
--brand-secondary: hsl(calc(var(--brand-hue) + 30), var(--brand-saturation), var(--brand-lightness));
--brand-accent: hsl(calc(var(--brand-hue) + 180), var(--brand-saturation), var(--brand-lightness));
/* Neutral Scale */
--gray-50: #fafafa;
--gray-100: #f5f5f5;
--gray-200: #e5e5e5;
--gray-300: #d4d4d4;
--gray-400: #a3a3a3;
--gray-500: #737373;
--gray-600: #525252;
--gray-700: #404040;
--gray-800: #262626;
--gray-900: #171717;
/* Semantic Surface Tokens */
--surface-base: #ffffff;
--surface-elevated: #fafafa;
--surface-overlay: #f5f5f5;
--text-main: #121212;
--text-secondary: #525252;
--text-tertiary: #737373;
--border-color: #e5e5e5;
}
.dark {
--surface-base: #121212;
--surface-elevated: #1a1a1a;
--surface-overlay: #262626;
--text-main: #f5f5f5;
--text-secondary: #a3a3a3;
--text-tertiary: #737373;
--border-color: #404040;
}Best for programmatic color manipulation and theming.
:root {
--primary-hue: 220;
--primary: hsl(var(--primary-hue), 90%, 56%);
--primary-dark: hsl(var(--primary-hue), 90%, 40%);
--primary-light: hsl(var(--primary-hue), 90%, 75%);
}Best for opacity and color mixing.
:root {
--primary-rgb: 59, 130, 246;
--primary: rgb(var(--primary-rgb));
--primary-alpha: rgba(var(--primary-rgb), 0.5);
}Best for perceptual uniformity and accessibility.
:root {
--primary: oklch(0.65 0.25 250);
--primary-dark: oklch(0.55 0.25 250);
--primary-light: oklch(0.85 0.15 250);
}Single hue with varying lightness/saturation.
:root {
--mono-50: hsl(220, 90%, 97%);
--mono-100: hsl(220, 90%, 92%);
--mono-200: hsl(220, 85%, 80%);
--mono-300: hsl(220, 80%, 65%);
--mono-400: hsl(220, 75%, 50%);
--mono-500: hsl(220, 70%, 35%);
--mono-600: hsl(220, 65%, 25%);
--mono-700: hsl(220, 60%, 18%);
--mono-800: hsl(220, 55%, 12%);
--mono-900: hsl(220, 50%, 8%);
}Adjacent hues on the color wheel (harmonious).
:root {
--analogous-1: hsl(200, 85%, 50%); /* Blue */
--analogous-2: hsl(220, 85%, 50%); /* Blue-Purple */
--analogous-3: hsl(240, 85%, 50%); /* Purple */
--analogous-4: hsl(260, 85%, 50%); /* Purple-Pink */
}Opposite hues (high contrast).
:root {
--complementary-1: hsl(220, 85%, 50%); /* Blue */
--complementary-2: hsl(40, 85%, 50%); /* Orange */
}Three hues evenly spaced (balanced).
:root {
--triadic-1: hsl(0, 85%, 50%); /* Red */
--triadic-2: hsl(120, 85%, 50%); /* Green */
--triadic-3: hsl(240, 85%, 50%); /* Blue */
}Base hue + two adjacent to its complement.
:root {
--split-1: hsl(220, 85%, 50%); /* Blue */
--split-2: hsl(10, 85%, 50%); /* Red-Orange */
--split-3: hsl(70, 85%, 50%); /* Yellow-Green */
}:root {
--success: hsl(142, 76%, 36%);
--success-light: hsl(142, 76%, 90%);
--warning: hsl(38, 92%, 50%);
--warning-light: hsl(38, 92%, 95%);
--error: hsl(0, 84%, 60%);
--error-light: hsl(0, 84%, 95%);
--info: hsl(199, 89%, 48%);
--info-light: hsl(199, 89%, 95%);
}:root {
--action-primary: var(--brand-primary);
--action-secondary: var(--brand-secondary);
--action-tertiary: var(--gray-500);
--focus-ring: hsl(220, 90%, 56%);
--selection-bg: hsl(220, 90%, 90%);
--link-color: hsl(220, 90%, 56%);
--visited-color: hsl(280, 60%, 55%);
}- Normal text: 4.5:1 contrast ratio
- Large text (18pt+): 3:1 contrast ratio
- UI components: 3:1 contrast ratio
:root {
--text-on-primary: #ffffff; /* Ensure 4.5:1 contrast */
--text-on-surface: #121212; /* Ensure 4.5:1 contrast */
}
/* High contrast mode support */
@media (prefers-contrast: high) {
:root {
--text-on-primary: #ffffff;
--text-on-surface: #000000;
--border-color: #000000;
}
}:root {
/* Avoid relying solely on color */
--success-pattern: repeating-linear-gradient(45deg, var(--success), var(--success) 2px, transparent 2px, transparent 4px);
--error-pattern: repeating-linear-gradient(45deg, var(--error), var(--error) 2px, transparent 2px, transparent 4px);
}Simple lightness inversion for dark mode.
.dark {
--surface-base: #121212;
--text-main: #f5f5f5;
--border-color: #404040;
}Reduce saturation in dark mode for eye comfort.
.dark {
--brand-primary: hsl(var(--brand-hue), 60%, var(--brand-lightness));
--text-secondary: hsl(0, 0%, 70%);
}Use tints of brand colors for dark mode.
.dark {
--brand-primary: hsl(var(--brand-hue), 70%, 65%);
--surface-base: #1a1a2e;
--surface-elevated: #16213e;
}:root {
--opacity-0: 0;
--opacity-10: 0.1;
--opacity-20: 0.2;
--opacity-30: 0.3;
--opacity-40: 0.4;
--opacity-50: 0.5;
--opacity-60: 0.6;
--opacity-70: 0.7;
--opacity-80: 0.8;
--opacity-90: 0.9;
--opacity-100: 1;
}:root {
--blend-normal: normal;
--blend-multiply: multiply;
--blend-screen: screen;
--blend-overlay: overlay;
--blend-darken: darken;
--blend-lighten: lighten;
}- Use semantic naming: Name colors by purpose, not appearance
- Maintain consistency: Use the same colors for similar purposes
- Test accessibility: Verify contrast ratios meet WCAG standards
- Support dark mode: Provide dark mode variants for all colors
- Document usage: Include guidelines for when to use each color
- Limit palette size: Use 5-7 primary colors maximum
- Consider cultural meanings: Be aware of color symbolism in different cultures
- Test at scale: Verify colors work across different contexts and sizes