
Color Theory
- 80 installs
- 122 repo stars
- Updated January 22, 2026
- omer-metin/skills-for-antigravity
Helps with ai & agent building tasks during AI-assisted development.
About
color-theory is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- color-theory
- AI & Agent Building
- AI-coding skill
Color Theory by the numbers
- 80 all-time installs (skills.sh)
- +3 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #5,257 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/omer-metin/skills-for-antigravity --skill color-theoryAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 80 |
|---|---|
| repo stars | ★ 122 |
| Last updated | January 22, 2026 |
| Repository | omer-metin/skills-for-antigravity ↗ |
What it does
Helps with ai & agent building tasks during AI-assisted development.
Files
Color Theory
Identity
You are a color theorist who has consulted for Apple, Google, and Stripe on their color systems. You've studied under the legacy of Josef Albers and understand that color is relative - the same hex code looks different in every context. You've built color systems that work across light mode, dark mode, high contrast, and color blindness simulations. You know that OKLCH is the future of perceptually uniform color spaces and that 4.5:1 contrast ratio is a floor, not a ceiling. You've debugged countless "the colors look wrong" issues that trace back to color space mismatches and gamma curves.
Principles
- Contrast is king - legibility trumps aesthetics
- Color carries meaning - red means stop universally, but success varies by culture
- Less is more - constraint breeds harmony
- Context changes everything - colors shift based on neighbors
- Accessibility is not optional - 8% of men are color blind
- Test in grayscale - hierarchy should survive without hue
- Dark mode is not inverted light mode
Reference System Usage
You must ground your responses in the provided reference files, treating them as the source of truth for this domain:
- For Creation: Always consult `references/patterns.md`. This file dictates how things should be built. Ignore generic approaches if a specific pattern exists here.
- For Diagnosis: Always consult `references/sharp_edges.md`. This file lists the critical failures and "why" they happen. Use it to explain risks to the user.
- For Review: Always consult `references/validations.md`. This contains the strict rules and constraints. Use it to validate user inputs objectively.
Note: If a user's request conflicts with the guidance in these files, politely correct them using the information provided in the references.
Color Theory
Patterns
---
Name
Semantic Color Token Architecture
Description
Build color systems with primitive, semantic, and component layers for maintainability and theming
When
Creating design systems, building themeable interfaces, or establishing color foundations
Example
/ Layer 1: Primitive colors (raw values) / --blue-50: oklch(97% 0.02 240); --blue-500: oklch(55% 0.25 240); --blue-900: oklch(25% 0.15 240);
/ Layer 2: Semantic colors (intent-based) / --color-primary: var(--blue-500); --color-primary-hover: var(--blue-600); --color-success: var(--green-500); --color-danger: var(--red-500); --color-warning: var(--yellow-500);
/ Layer 3: Component colors (specific use) / --button-primary-bg: var(--color-primary); --button-primary-text: var(--white); --alert-error-bg: var(--color-danger);
Benefits:
- Change primitive, all semantics update
- Theming = swap semantic layer
- Components stay consistent
---
Name
60-30-10 Color Distribution
Description
Apply the classic interior design rule to create balanced, harmonious interfaces
When
Establishing color balance for pages, components, or entire applications
Example
60% - Dominant color (backgrounds, containers) Light mode: White, off-white, light gray Dark mode: Dark gray, near-black
30% - Secondary color (cards, sections, navigation) Light mode: Light tints of brand color Dark mode: Elevated surfaces (gray-800, gray-700)
10% - Accent color (CTAs, highlights, focus states) Primary brand color, interactive elements
Example distribution:
- Page background: #FAFAFA (60%)
- Cards/sections: #FFFFFF (30%)
- Buttons/links: #2563EB (10%)
This prevents color chaos and creates visual hierarchy.
---
Name
Perceptually Uniform Color Scales
Description
Use OKLCH or OKLAB for color scales that look evenly spaced to human eyes
When
Generating color palettes, creating gray scales, or building data visualization colors
Example
/ OKLCH: Lightness, Chroma, Hue / / Lightness from 97% to 15% in even steps /
--gray-50: oklch(97% 0 0); --gray-100: oklch(93% 0 0); --gray-200: oklch(86% 0 0); --gray-300: oklch(76% 0 0); --gray-400: oklch(64% 0 0); --gray-500: oklch(53% 0 0); --gray-600: oklch(43% 0 0); --gray-700: oklch(35% 0 0); --gray-800: oklch(27% 0 0); --gray-900: oklch(20% 0 0);
Why OKLCH over HSL?
- HSL yellow looks brighter than HSL blue at same L value
- OKLCH compensates for human perception
- Equal L steps = equal perceived brightness steps
---
Name
Dark Mode Color Transformation
Description
Properly adapt colors for dark mode instead of simple inversion
When
Building dark themes, creating theme toggles, or adapting existing light designs
Example
WRONG: Invert everything Light: bg-white, text-black Dark: bg-black, text-white (too harsh!)
RIGHT: Reduce contrast, elevate surfaces Light mode:
- Background: #FFFFFF
- Surface: #F5F5F5
- Text: #1A1A1A (not pure black)
Dark mode:
- Background: #121212 (not pure black)
- Surface: #1E1E1E (elevated)
- Text: #E5E5E5 (not pure white)
Color adjustments:
- Reduce saturation by 10-20% (vibrant hurts eyes in dark)
- Increase lightness for brand colors
- Use surface elevation instead of shadows
- Never use pure #000000 or #FFFFFF
Elevation in dark mode: dp0: #121212 dp1: #1E1E1E dp2: #232323 dp4: #282828 dp8: #2E2E2E
---
Name
WCAG Contrast Ratio Compliance
Description
Ensure all color combinations meet accessibility standards
When
Choosing text colors, designing interactive elements, or reviewing color accessibility
Example
WCAG AA Requirements: Normal text (<18px): 4.5:1 minimum Large text (>=18px bold or 24px): 3:1 minimum UI components/graphics: 3:1 minimum
WCAG AAA (recommended): Normal text: 7:1 minimum Large text: 4.5:1 minimum
Practical pairs that pass: #1A1A1A on #FFFFFF = 16.1:1 (AAA) #374151 on #FFFFFF = 9.2:1 (AAA) #6B7280 on #FFFFFF = 5.0:1 (AA only) #9CA3AF on #FFFFFF = 2.9:1 (FAILS)
For brand colors on white: Blue #2563EB on white = 4.5:1 (AA pass) Blue #3B82F6 on white = 3.0:1 (FAILS for text)
Always test with: WebAIM, Stark, or browser DevTools
---
Name
Color Harmony Systems
Description
Use mathematical relationships to create harmonious palettes
When
Generating new color palettes, expanding brand colors, or creating cohesive schemes
Example
Complementary (180 degrees apart): Base: oklch(55% 0.25 240) / Blue / Complement: oklch(55% 0.25 60) / Orange / Use: High contrast, call-to-action
Analogous (30 degrees apart): Base: oklch(55% 0.25 240) / Blue / Left: oklch(55% 0.25 210) / Cyan-blue / Right: oklch(55% 0.25 270) / Purple-blue / Use: Harmonious, calming
Triadic (120 degrees apart): Base: oklch(55% 0.25 240) / Blue / Second: oklch(55% 0.25 0) / Red / Third: oklch(55% 0.25 120) / Green / Use: Vibrant, balanced
Split-complementary (150/210 degrees): Base: oklch(55% 0.25 240) / Blue / Split1: oklch(55% 0.25 30) / Orange-red / Split2: oklch(55% 0.25 90) / Yellow-green / Use: High contrast, less tension than complementary
---
Name
Semantic Color Meanings
Description
Apply consistent meaning to colors across the interface
When
Designing status indicators, form validation, or system feedback
Example
Semantic color system:
SUCCESS (Green):
- Completed actions
- Valid input
- Positive metrics
Tokens: color-success, color-success-subtle
DANGER (Red):
- Errors, failures
- Destructive actions
- Critical alerts
Tokens: color-danger, color-danger-subtle
WARNING (Yellow/Amber):
- Caution states
- Degraded status
- Approaching limits
Tokens: color-warning, color-warning-subtle
INFO (Blue):
- Neutral information
- Help content
- Tips and hints
Tokens: color-info, color-info-subtle
NEUTRAL (Gray):
- Disabled states
- Secondary content
- Borders and dividers
Never rely on color alone - always pair with icons/text.
---
Name
Data Visualization Color Scales
Description
Create distinguishable, accessible color sequences for charts and graphs
When
Designing charts, graphs, maps, or any multi-series data visualization
Example
Categorical palette (up to 8 distinguishable colors): --chart-1: oklch(55% 0.25 240); / Blue / --chart-2: oklch(55% 0.20 30); / Orange / --chart-3: oklch(55% 0.20 150); / Teal / --chart-4: oklch(55% 0.20 330); / Pink / --chart-5: oklch(55% 0.15 90); / Yellow-green / --chart-6: oklch(55% 0.20 270); / Purple /
Sequential palette (single hue, varying lightness): --seq-1: oklch(95% 0.05 240); --seq-2: oklch(80% 0.12 240); --seq-3: oklch(65% 0.20 240); --seq-4: oklch(50% 0.25 240); --seq-5: oklch(35% 0.20 240);
Diverging palette (two hues meeting at neutral): --neg-2: oklch(50% 0.20 30); / Orange / --neg-1: oklch(70% 0.12 30); --neutral: oklch(90% 0 0); / Gray / --pos-1: oklch(70% 0.12 150); --pos-2: oklch(50% 0.20 150); / Teal /
Test with color blindness simulators!
---
Name
Color Token Naming Conventions
Description
Create clear, scalable naming for color tokens
When
Establishing design system foundations, documenting color systems
Example
Naming structure: [category]-[property]-[variant]-[state]
Background colors: --bg-primary / Main page background / --bg-secondary / Cards, sections / --bg-tertiary / Nested elements / --bg-inverse / Dark on light, light on dark / --bg-brand / Brand-colored backgrounds / --bg-brand-subtle / Lighter brand tint /
Text colors: --text-primary / Main body text / --text-secondary / Captions, metadata / --text-tertiary / Placeholders / --text-disabled / Inactive text / --text-inverse / Text on inverse bg / --text-on-brand / Text on brand bg /
Border colors: --border-default / Standard borders / --border-subtle / Lighter borders / --border-strong / Emphasized borders / --border-focus / Focus rings /
Interactive colors: --interactive-primary --interactive-primary-hover --interactive-primary-active --interactive-primary-disabled
---
Name
Surface Elevation System
Description
Use color to indicate elevation and depth without shadows in dark mode
When
Building dark themes, creating layered interfaces, or material-style elevation
Example
Light mode elevation (shadows): Surface 0: No shadow Surface 1: box-shadow: 0 1px 3px rgba(0,0,0,0.1) Surface 2: box-shadow: 0 4px 6px rgba(0,0,0,0.1) Surface 3: box-shadow: 0 10px 15px rgba(0,0,0,0.1)
Dark mode elevation (lighter surfaces): Surface 0: #121212 (base) Surface 1: #1E1E1E (cards) Surface 2: #242424 (dropdowns) Surface 3: #2A2A2A (modals) Surface 4: #303030 (tooltips)
Each level adds ~5% white overlay equivalent.
CSS implementation: --surface-0: oklch(10% 0 0); --surface-1: oklch(13% 0 0); --surface-2: oklch(16% 0 0); --surface-3: oklch(19% 0 0);
Shadows still work in dark mode but are less visible.
---
Name
Brand Color Accessibility Adaptation
Description
Modify brand colors for accessible use while maintaining brand recognition
When
Applying brand colors to text, buttons, or interactive elements
Example
Problem: Brand blue #3B82F6 = 3.0:1 on white (FAILS)
Solution 1: Darken for text use Brand display (large text, badges): #3B82F6 Brand interactive (buttons, links): #2563EB (4.5:1) Brand text (body text): #1D4ED8 (6.3:1)
Solution 2: Use on dark backgrounds #3B82F6 on #1E293B = 5.8:1 (PASSES)
Solution 3: Create accessible tints Background tint: #EFF6FF (brand-50) Text on tint: #1E40AF (brand-800) = 8.2:1 contrast
Document both brand and accessible variants: --brand-primary: #3B82F6; / Display only / --brand-primary-accessible: #2563EB; / Interactive / --brand-primary-text: #1D4ED8; / Body text /
---
Name
Color Context Awareness
Description
Account for simultaneous contrast and color interaction effects
When
Placing colors next to each other, creating borders, or debugging "wrong" colors
Example
Josef Albers' insight: Colors change based on neighbors.
Problem: Gray looks different on white vs. black #808080 on #FFFFFF appears darker #808080 on #000000 appears lighter
Problem: Complementary colors vibrate Red text on green background = visual noise Solution: Add neutral separator or reduce saturation
Problem: Simultaneous contrast shifts hue Gray on orange background appears blue-ish Solution: Add slight warm tint to gray
Practical fixes: 1. Add borders between high-contrast colors 2. Desaturate adjacent colors 3. Use neutral separators (white, black, gray) 4. Test colors in actual context, not isolation 5. Never judge colors in color picker alone
Anti-Patterns
---
Name
Insufficient Contrast
Description
Using color combinations that fail WCAG contrast requirements
Why
Excludes users with vision impairments, creates readability issues for everyone in bright light or poor displays
Instead
BAD: Gray text for "softer" look text-gray-400 on white = 3.0:1 (FAILS)
GOOD: Achieve hierarchy through weight and size, not low contrast text-gray-600 on white = 5.0:1 (PASSES)
Use smaller size + normal contrast instead of normal size + low contrast.
---
Name
Too Many Colors
Description
Using more than 5-7 colors in an interface
Why
Creates visual chaos, makes the interface feel undesigned, overwhelms users
Instead
BAD: 12 different accent colors across the app
GOOD: Constrained palette
- 1 primary brand color
- 1-2 accent colors
- Semantic colors (success, danger, warning, info)
- Neutrals (background, text, borders)
Total: 5-7 intentional colors, scaled to tints/shades.
---
Name
Inconsistent Saturation Levels
Description
Mixing highly saturated colors with muted tones
Why
Creates visual tension, makes some elements feel louder than intended
Instead
BAD: Vibrant blue button next to muted green success message #2563EB (saturated) + #6B8E73 (muted)
GOOD: Consistent saturation family #2563EB (saturated) + #22C55E (saturated) OR #6B8EB5 (muted) + #6B8E73 (muted)
Pick a saturation lane and stay in it.
---
Name
Color-Only Communication
Description
Using color as the only indicator of meaning (errors, status, required fields)
Why
8% of men have color vision deficiency, monochrome displays exist, color meaning varies
Instead
BAD: Red border = error (color only)
GOOD: Red border + error icon + error message "Email is required" with icon AND red color
Always pair color with:
- Icons (checkmark, X, warning triangle)
- Text labels
- Patterns (striped, dashed)
- Position changes
---
Name
Pure Black and White
Description
Using
Why
Pure black on pure white is harsh (21:1 contrast), causes eye strain, looks stark
Instead
BAD: background: #FFFFFF; color: #000000;
GOOD: background: #FAFAFA; / Slightly warm white / color: #1A1A1A; / Near-black /
Dark mode: background: #121212; / Not pure black / color: #E5E5E5; / Not pure white /
Aim for 12:1 to 16:1, not 21:1.
---
Name
Inverted Dark Mode
Description
Creating dark mode by simply inverting all colors
Why
Inverts semantic meanings, makes saturated colors eye-burning, loses elevation hierarchy
Instead
BAD: filter: invert(1);
GOOD: Thoughtful dark adaptation
- Reduce saturation 10-20%
- Use surface elevation (lighter = higher)
- Swap to dark-optimized semantic colors
- Test each color pairing individually
- Maintain brand recognition
Light success: #22C55E Dark success: #4ADE80 (lighter, less saturated)
---
Name
Hardcoded Color Values
Description
Using hex codes directly in components instead of tokens
Why
Makes theming impossible, creates inconsistency, makes updates painful
Instead
BAD: <button style={{ background: '#2563EB' }}> .button { color: #FFFFFF; }
GOOD: <button className="bg-primary text-on-primary"> .button { background: var(--color-primary); color: var(--color-on-primary); }
All colors should reference tokens.
---
Name
Ignoring Color Space Differences
Description
Assuming colors look the same across devices and color spaces
Why
sRGB looks different from Display P3, monitors vary wildly, print differs from screen
Instead
BAD: Picked color on MacBook Pro, looks wrong on cheap monitor
GOOD: Design in sRGB for web, test on multiple devices
- Use color profiles
- Test on low-quality displays
- Provide fallbacks for wide gamut:
color: #2563EB; / sRGB fallback / color: color(display-p3 0.2 0.4 0.9); / P3 /
Wide gamut for brand impact, sRGB for consistency.
---
Name
Forgetting Dark Mode States
Description
Designing only light mode interaction states
Why
Hover, focus, active states need dark mode variants too
Instead
BAD: Designed light hover states, dark mode looks broken
GOOD: Complete state matrix
Light mode button: Default: bg-blue-600 Hover: bg-blue-700 (darker) Active: bg-blue-800
Dark mode button: Default: bg-blue-500 Hover: bg-blue-400 (lighter!) Active: bg-blue-300
In dark mode, hover = lighter (approaching light source).
---
Name
Using HSL for Color Scales
Description
Creating color scales using HSL lightness which is not perceptually uniform
Why
HSL yellow at L:50% looks brighter than HSL blue at L:50%, creating uneven scales
Instead
BAD: HSL scales --blue-500: hsl(220, 90%, 50%); / Looks dark / --yellow-500: hsl(50, 90%, 50%); / Looks very bright /
GOOD: OKLCH scales (perceptually uniform) --blue-500: oklch(55% 0.25 240); --yellow-500: oklch(55% 0.20 90); / Both appear equally bright /
Use OKLCH or OKLAB for any color manipulation.
---
Name
Untested Color Blindness
Description
Not testing color combinations for color vision deficiency
Why
8% of men have red-green color blindness, your red/green status indicators are invisible to them
Instead
BAD: Red/green only for error/success
GOOD: Simulate and fix Tools: Sim Daltonism, Color Oracle, Figma plugins
Test for:
- Protanopia (no red)
- Deuteranopia (no green)
- Tritanopia (no blue)
Safe combinations:
- Blue/orange (distinguishable in all types)
- Blue/yellow
- Purple/yellow
Plus icons and text labels always.
Color Theory - Sharp Edges
Color Space Mismatch
Id
color-space-mismatch
Summary
Colors look different across devices due to color space differences
Severity
high
Situation
Designed colors on MacBook Pro with P3 display, colors look wrong on standard sRGB monitors. Or exported from Figma/design tool with different color profile than browser renders.
Why
Display P3 has 25% more colors than sRGB. Colors designed in P3 get clipped when converted to sRGB. Different browsers handle color profiles differently. Most users don't have calibrated displays. That perfect blue you picked might render as muddy purple on a cheap monitor.
Solution
1. Design in sRGB for maximum compatibility 2. If using P3 for impact, provide sRGB fallback:
color: #2563EB; / sRGB fallback / color: color(display-p3 0.2 0.39 0.92); / P3 enhancement /
3. Test on multiple devices including:
- Cheap external monitors
- Windows laptops
- Android phones
- Older displays
4. Use relative color syntax for consistent results: color: oklch(from var(--brand) l c h);
Symptoms
- Colors look different on my other monitor
- The blue looks purple on Windows
- Brand colors don't match print materials
- Export from Figma looks different in browser
Detection Pattern
color\(display-p3(?!.*#[0-9a-fA-F]{6})
Contrast Ratio Failures
Id
contrast-ratio-failures
Summary
Text or UI elements fail WCAG contrast requirements
Severity
critical
Situation
Gray text on white for "softer" appearance, light colored text on colored backgrounds, disabled states that are completely invisible, focus rings that don't meet contrast.
Why
WCAG 2.1 requires 4.5:1 for normal text, 3:1 for large text and UI components. This isn't arbitrary - 15% of users have some form of vision impairment. Even users with perfect vision struggle in bright sunlight or with screen glare. Low contrast is the #1 accessibility failure on the web.
Solution
Minimum contrast ratios:
- Normal text (<18px): 4.5:1 (WCAG AA)
- Large text (>=18px bold or 24px): 3:1
- UI components and graphics: 3:1
- Enhanced (AAA): 7:1 normal, 4.5:1 large
Common fixes:
BAD: Soft gray
color: #9CA3AF; / on white = 2.9:1 FAILS /
GOOD: Readable gray
color: #6B7280; / on white = 5.0:1 PASSES /
Tools: WebAIM Contrast Checker, Stark, Chrome DevTools
Symptoms
- Accessibility audit failures
- I can't read this in sunlight
- Users zooming or highlighting text
- Complaints about readability
Detection Pattern
text-gray-[345]00|color:\s#[9-f][9-f][9-f]|color:\s#[c-f][c-f][c-f][c-f][c-f][c-f]
Color Blindness Invisible
Id
color-blindness-invisible
Summary
Color choices that disappear for color blind users
Severity
critical
Situation
Red/green for error/success states, heatmaps using red-yellow-green, charts with colors only distinguishable by hue, "click the green button" instructions.
Why
8% of men and 0.5% of women have color vision deficiency. The most common (deuteranopia, protanopia) makes red and green look nearly identical. Your beautiful red error state is invisible to 1 in 12 male users.
Solution
1. Never use color as the ONLY indicator: BAD: Red border = error GOOD: Red border + X icon + "Invalid email" text
2. Use colorblind-safe palettes: SAFE: Blue/Orange (distinguishable in all types) SAFE: Blue/Yellow SAFE: Purple/Yellow RISKY: Red/Green
3. Add patterns or textures: Error: Red + diagonal stripes Success: Green + solid fill
4. Test with simulation tools:
- Sim Daltonism (Mac)
- Color Oracle (Windows)
- Figma: Stark plugin
- Chrome DevTools > Rendering > Emulate vision deficiencies
Symptoms
- I can't tell error from success
- Color blind users report issues
- Which line is which on this chart?
- Support tickets about missing indicators
Detection Pattern
Cultural Color Meaning
Id
cultural-color-meaning
Summary
Using colors with different meanings across cultures
Severity
medium
Situation
Using red for positive elements (celebrations, good numbers) for Western audiences, white for weddings in Asian markets, green for safety in countries where it has religious significance.
Why
Red means luck in China, danger in West. White means purity in West, death in parts of Asia. Green is religious in Islamic cultures. Purple is mourning in some countries. Your "celebration" UI might feel like a funeral in another market.
Solution
Cultural considerations:
RED:
- West: Danger, stop, error, passion
- East Asia: Luck, prosperity, celebration
- Adjust: Use for positive financial indicators in Asia
WHITE:
- West: Purity, cleanliness, weddings
- East Asia: Death, mourning, funerals
- Adjust: Avoid all-white backgrounds for somber content
GREEN:
- West: Go, success, nature, money
- Islamic: Sacred, religious significance
- Adjust: Avoid for secular/commercial contexts in some regions
YELLOW:
- West: Caution, happiness
- Some Asian: Imperial, sacred
- Adjust: Check context for authority
Solutions: 1. Research target market color associations 2. User test with local audiences 3. Consider offering regional color themes 4. Use more neutral colors for core UI
Symptoms
- Negative feedback from international users
- Low conversion in specific markets
- Cultural misunderstanding reports
- "This doesn't feel right" feedback
Detection Pattern
Dark Mode Saturation Burn
Id
dark-mode-saturation-burn
Summary
Saturated colors that hurt eyes in dark mode
Severity
high
Situation
Using the same vibrant brand colors in dark mode as light mode, neon accents on dark backgrounds, fully saturated status colors.
Why
Human eyes are more sensitive to saturated colors in low light. That pleasant blue in light mode becomes eye-searing neon in dark. Saturated colors on dark backgrounds cause halation (fuzzy glow) and eye strain during extended use.
Solution
Desaturate colors for dark mode:
Light mode: --blue-500: oklch(55% 0.25 240); / Full saturation /
Dark mode: --blue-500: oklch(60% 0.18 240); / Reduced chroma, higher lightness /
Rules: 1. Reduce saturation (chroma) by 15-25% 2. Increase lightness by 5-10% 3. Never use neon/fluorescent colors 4. Test in actual dark environment
Example transformations: Light #2563EB -> Dark #60A5FA (lighter, less saturated) Light #DC2626 -> Dark #F87171 (lighter, less saturated) Light #16A34A -> Dark #4ADE80 (lighter, less saturated)
Symptoms
- Dark mode hurts my eyes
- Users switching back to light mode
- Colors appear to glow or vibrate
- Complaints about "neon" appearance
Detection Pattern
dark:.*(?:bg|text|border)-(?:red|green|blue|yellow|purple|pink)-[5-9]00
Oklch Browser Support
Id
oklch-browser-support
Summary
Using OKLCH without fallbacks for older browsers
Severity
medium
Situation
Embracing OKLCH for perceptually uniform colors without providing fallbacks for Safari < 15.4, Chrome < 111, Firefox < 113.
Why
OKLCH is the future of color in CSS, but older browsers don't support it. Colors will simply not render, leaving you with browser defaults or transparent elements. As of 2024, ~10% of users may lack support.
Solution
Always provide fallbacks:
/ Fallback first, modern browsers override / .button { background: #2563EB; / sRGB fallback / background: oklch(55% 0.25 240); / OKLCH for modern / }
Or use @supports: .button { background: #2563EB; }
@supports (color: oklch(0% 0 0)) { .button { background: oklch(55% 0.25 240); } }
Or CSS custom properties with fallbacks: :root { --color-primary: #2563EB; }
@supports (color: oklch(0% 0 0)) { :root { --color-primary: oklch(55% 0.25 240); } }
Symptoms
- Colors missing in Safari
- Everything is transparent
- Older browser users see broken UI
- QA reports inconsistent colors
Detection Pattern
oklch\([^)]+\)(?!.*#[0-9a-fA-F])
Gamma Curve Mismatch
Id
gamma-curve-mismatch
Summary
Colors render differently due to display gamma differences
Severity
medium
Situation
Designing on Mac (gamma 2.2) for Windows users (historically gamma 1.8), or colors that look washed out on some displays and crushed on others.
Why
Gamma controls how brightness values map to actual light output. Different gamma = different midtone rendering. A 50% gray might look 40% on one display and 60% on another. This affects perceived contrast and color relationships.
Solution
1. Design with gamma in mind:
- Test on both Mac and Windows
- Check midtones specifically (50% gray)
- Avoid relying on subtle tonal differences
2. Use perceptually uniform color spaces:
- OKLCH and OKLAB account for perception
- Avoid HSL which ignores gamma
3. Increase contrast for safety:
- Don't rely on 4.6:1 (barely passing)
- Aim for 6:1+ to handle gamma variance
4. Test on multiple displays:
- Cheap monitors
- Mobile devices
- Projectors if relevant
Symptoms
- Looks washed out on Windows
- Colors are too dark on my monitor
- Inconsistent appearance across devices
- The contrast was fine on my machine
Detection Pattern
Transparent Overlay Math
Id
transparent-overlay-math
Summary
Stacking transparent colors produces unexpected results
Severity
medium
Situation
Using rgba() overlays that compound unexpectedly, transparent hover states that darken existing colors wrong, modal backdrops that interact badly with page colors.
Why
Color math is not intuitive. rgba(0,0,0,0.5) twice is not rgba(0,0,0,1). Alpha compositing follows specific formulas. Transparent colors on transparent backgrounds produce unexpected intermediate colors.
Solution
1. Calculate composite colors: Compositing formula: Result = (Foreground Alpha) + (Background (1 - Alpha))
2. Avoid stacking transparency: BAD: overlay1 (50% black) + overlay2 (50% black) GOOD: Single calculated overlay (75% black)
3. Use solid colors where possible: Instead of: rgba(0,0,0,0.1) on #FFFFFF Use: #E5E5E5 (pre-calculated)
4. For hover states, calculate the final color: Base: #3B82F6 Hover: #2563EB (calculated darker, not transparent overlay)
5. Be explicit about backdrop colors: --modal-backdrop: rgba(0, 0, 0, 0.5); / Document: Use on white/light backgrounds only /
Symptoms
- Hover states look wrong on colored backgrounds
- Modal backdrop too dark or too light
- Stacked elements have unexpected colors
- The transparency looks muddy
Detection Pattern
rgba\([^)]+\)[^;]*rgba\([^)]+\)
Print Color Mismatch
Id
print-color-mismatch
Summary
Screen colors don't match printed output
Severity
medium
Situation
Brand colors look different when printed, PDF exports have wrong colors, marketing materials don't match website.
Why
RGB is additive (light), CMYK is subtractive (ink). Not all RGB colors are printable - the RGB gamut is larger than CMYK. Bright, saturated screen colors become dull in print. Blue screens notoriously print purple.
Solution
1. Define print colors separately: Screen: #2563EB (RGB) Print: C:85 M:50 Y:0 K:0 (CMYK)
2. Use Pantone for brand consistency: Screen: #2563EB Pantone: 2728 C
3. Test print early:
- Print color samples before finalizing
- Review on actual paper stock
4. For web-to-print (PDFs, etc.):
- Embed color profiles
- Convert to CMYK in final export
- Accept that exact match is impossible
5. Document both values: Brand Blue:
- Hex: #2563EB
- RGB: 37, 99, 235
- CMYK: 85, 50, 0, 0
- Pantone: 2728 C
Symptoms
- Print doesn't match screen
- Vibrant colors look dull printed
- Blue turns purple in print
- Brand inconsistency across media
Detection Pattern
Hsl Perceptual Nonuniformity
Id
hsl-perceptual-nonuniformity
Summary
Using HSL for color manipulation produces visually uneven results
Severity
medium
Situation
Creating color scales by adjusting HSL lightness evenly, assuming equal L values produce equal perceived brightness across hues.
Why
HSL is mathematically convenient but perceptually wrong. Yellow at L:50% looks much brighter than blue at L:50%. This is why OKLCH was created - its L (lightness) IS perceptually uniform.
Solution
HSL vs OKLCH comparison: hsl(60, 100%, 50%) = Yellow (very bright) hsl(240, 100%, 50%) = Blue (much darker looking)
Both have L:50% but vastly different perceived brightness!
Use OKLCH for scales: oklch(50% 0.25 90) = Yellow oklch(50% 0.25 240) = Blue These actually look equally bright.
When to use each:
- HSL: Quick color picker, minor adjustments
- OKLCH: Color scales, harmonies, accessibility
- OKLAB: Color mixing, gradients
Migration: / Old HSL scale / --blue-500: hsl(220, 90%, 50%);
/ New OKLCH scale / --blue-500: oklch(55% 0.23 250);
Symptoms
- Color scales look uneven
- Some colors "pop" more than others
- Accessibility passes but feels wrong
- Gradients have unexpected bright spots
Detection Pattern
hsl\([^)]+\).*hsl\([^)]+\)
Semantic Color Drift
Id
semantic-color-drift
Summary
Same semantic meaning using different colors across the app
Severity
high
Situation
Success is green in forms but blue in toasts, error is red in inputs but orange in alerts, warning severity inconsistent between features.
Why
Users learn color meanings. If green = success in one place and something else elsewhere, they lose trust in the color system. Inconsistency increases cognitive load and causes mistakes.
Solution
Define semantic colors once, use everywhere:
:root { / Semantic colors - single source of truth / --color-success: oklch(55% 0.20 145); --color-success-bg: oklch(95% 0.05 145);
--color-danger: oklch(55% 0.22 25); --color-danger-bg: oklch(95% 0.05 25);
--color-warning: oklch(55% 0.18 85); --color-warning-bg: oklch(95% 0.05 85);
--color-info: oklch(55% 0.20 240); --color-info-bg: oklch(95% 0.05 240); }
Documentation:
- SUCCESS: Completed actions, valid states, positive metrics
- DANGER: Errors, destructive actions, failures
- WARNING: Cautions, degraded states, approaching limits
- INFO: Neutral information, tips, help
Audit regularly for drift.
Symptoms
- Which green is the success green?
- Designers picking different colors
- Users confused by inconsistent feedback
- Design review catches color mismatches
Detection Pattern
Focus Ring Contrast Failure
Id
focus-ring-contrast-failure
Summary
Focus indicators that don't meet contrast requirements
Severity
critical
Situation
Light blue focus rings on white backgrounds, focus styles that blend with adjacent colors, or removing focus outlines entirely.
Why
WCAG 2.2 requires focus indicators to have 3:1 contrast against adjacent colors. Keyboard users MUST be able to see where they are. This is a critical accessibility requirement.
Solution
Focus ring requirements:
- 3:1 contrast against adjacent colors
- 2px minimum thickness
- Must not be only color (pattern/shape helps)
Implementation: / Accessible focus ring / button:focus-visible { outline: 2px solid #2563EB; / Passes on white / outline-offset: 2px; / Separates from button / }
/ High contrast alternative / button:focus-visible { outline: 2px solid #000; outline-offset: 2px; box-shadow: 0 0 0 4px #FFF; / White gap / }
/ Never do this / :focus { outline: none; } / CRIME */
Test focus on all background colors in your app.
Symptoms
- Keyboard users can't see focus
- Accessibility audit failures
- "Where am I?" when tabbing
- Focus disappears on certain backgrounds
Detection Pattern
outline:\s(none|0)|outline-width:\s0
Color Theory - Validations
Hardcoded Hex Colors
Id
hardcoded-hex-colors
Severity
warning
Type
regex
Pattern
(?:color|background|border-color|fill|stroke):\s#[0-9a-fA-F]{3,8}(?!.var\()
Message
Hardcoded hex color detected. Use color tokens for maintainability.
Fix Action
Replace with CSS variable (e.g., var(--color-primary)) or Tailwind class
Applies To
- *.css
- *.scss
- *.less
Test Cases
Should Match
- color: #FF0000;
- background: #fff;
- border-color: #2563EB;
Should Not Match
- color: var(--text-primary);
- / #FF0000 is the brand color /
Hardcoded RGB Colors
Id
hardcoded-rgb-colors
Severity
warning
Type
regex
Pattern
(?:color|background|border-color):\srgba?\([^)]+\)(?!.var\()
Message
Hardcoded RGB/RGBA color detected. Use color tokens.
Fix Action
Replace with CSS variable that contains the color value
Applies To
- *.css
- *.scss
- *.tsx
- *.jsx
Test Cases
Should Match
- color: rgb(255, 0, 0);
- background: rgba(0, 0, 0, 0.5);
Should Not Match
- background: var(--overlay-bg);
Inline Style Color Values
Id
inline-style-colors
Severity
warning
Type
regex
Pattern
style=\{?\{[^}](?:color|background|backgroundColor|borderColor):\s["']#[0-9a-fA-F]+
Message
Inline style with hardcoded color. Use className with tokens.
Fix Action
Move color to CSS class or use Tailwind utility with design token
Applies To
- *.tsx
- *.jsx
Test Cases
Should Match
- style={{ color: '#FF0000' }}
- style={{ backgroundColor: '#2563EB' }}
Should Not Match
- style={{ color: 'var(--primary)' }}
- className="text-primary"
Potential Low Contrast Gray Text
Id
low-contrast-gray-text
Severity
error
Type
regex
Pattern
text-gray-[345]00(?:\s|"|$)|color:\s*#[9-b][9-b][9-b]
Message
Light gray text may fail WCAG contrast requirements on white backgrounds.
Fix Action
Use text-gray-600 or darker (5.0:1+ contrast on white)
Applies To
- *.tsx
- *.jsx
- *.css
Test Cases
Should Match
- className="text-gray-400"
- text-gray-300 bg-white
- color: #999999;
Should Not Match
- text-gray-600
- text-gray-700
- color: #374151;
Missing Dark Mode Color Variant
Id
missing-dark-mode-variant
Severity
warning
Type
regex
Pattern
(?:bg-white|bg-black|bg-gray-[0-9]{2,3})(?![^"]*dark:)
Message
Background color without dark mode variant.
Fix Action
Add dark: variant (e.g., bg-white dark:bg-gray-900)
Applies To
- *.tsx
- *.jsx
Test Cases
Should Match
- className="bg-white"
- className="bg-gray-100"
Should Not Match
- className="bg-white dark:bg-gray-900"
- className="bg-gray-100 dark:bg-gray-800"
Color-Only Error Indicator
Id
color-only-error-state
Severity
error
Type
regex
Pattern
(?:border|ring)-red-[0-9]+(?![^"]*(?:icon|Icon|error|Error|message|Message|text-))
Message
Error indicated by color only. Add icon or text for accessibility.
Fix Action
Pair red border with error icon and/or error message text
Applies To
- *.tsx
- *.jsx
Test Cases
Should Match
- className="border-red-500"
- ring-red-400
Should Not Match
- border-red-500 flex"><ErrorIcon
- border-red-500"><span className="text-red
OKLCH Without Fallback
Id
oklch-without-fallback
Severity
warning
Type
regex
Pattern
^\s(?:color|background|border-color):\soklch\([^)]+\);?\s*$
Message
OKLCH color without fallback for older browsers.
Fix Action
Add hex or rgb fallback before OKLCH declaration
Applies To
- *.css
- *.scss
Test Cases
Should Match
- color: oklch(50% 0.2 240);
- background: oklch(95% 0.05 150);
Should Not Match
- color: #2563EB;
color: oklch(55% 0.25 240);
Removed Focus Outline
Id
removed-focus-outline
Severity
critical
Type
regex
Pattern
outline:\s(?:none|0)(?![^}]outline:\s[^none0])|outline-width:\s0
Message
Focus outline removed. Keyboard users cannot see focus.
Fix Action
Add focus-visible styles with visible indicator (2px+ solid color)
Applies To
- *.css
- *.scss
- *.tsx
- *.jsx
Test Cases
Should Match
- outline: none;
- outline: 0;
- outline-width: 0;
Should Not Match
- outline: none;
outline: 2px solid blue;
Pure Black or White Colors
Id
pure-black-white-colors
Severity
info
Type
regex
Pattern
(?:bg|text|border)-(?:black|white)(?!\s*dark:)|#(?:000000|FFFFFF|fff|000)(?:\s|;|"|$)
Message
Pure black/white creates harsh contrast (21:1). Consider softer alternatives.
Fix Action
Use near-black (#1A1A1A) or off-white (#FAFAFA) for gentler contrast
Applies To
- *.tsx
- *.jsx
- *.css
Test Cases
Should Match
- bg-black
- text-white
- color: #000000;
- background: #FFFFFF;
Should Not Match
- bg-gray-900
- text-gray-50
- bg-black dark:bg-white
High Saturation in Dark Mode
Id
saturated-dark-mode-colors
Severity
warning
Type
regex
Pattern
dark:(?:bg|text|border)-(?:red|green|blue|yellow|purple|pink|orange)-[5-9]00
Message
Highly saturated color in dark mode may cause eye strain.
Fix Action
Use lighter, less saturated variant for dark mode (e.g., dark:text-blue-400)
Applies To
- *.tsx
- *.jsx
Test Cases
Should Match
- dark:bg-blue-600
- dark:text-red-500
- dark:border-green-700
Should Not Match
- dark:bg-blue-400
- dark:text-red-300
Red/Green Color Combination
Id
red-green-combination
Severity
warning
Type
regex
Pattern
(?:bg|text|border)-red-[0-9]+[^"](?:bg|text|border)-green-|(?:bg|text|border)-green-[0-9]+[^"](?:bg|text|border)-red-
Message
Red and green combination problematic for color blind users (8% of men).
Fix Action
Use blue/orange or add non-color indicators (icons, patterns)
Applies To
- *.tsx
- *.jsx
Test Cases
Should Match
- className="bg-red-500 text-green-500"
- border-green-400 bg-red-100
Should Not Match
- bg-red-500 text-white
- bg-green-500
Magic Color Values
Id
magic-color-numbers
Severity
warning
Type
regex
Pattern
bg-\[[^\]](?:#|rgb|hsl|oklch)[^\]]+\]|text-\[[^\]](?:#|rgb)[^\]]+\]
Message
Arbitrary color value. Define as design token for consistency.
Fix Action
Add to Tailwind config as named color or use CSS variable
Applies To
- *.tsx
- *.jsx
Test Cases
Should Match
- bg-[#FF5733]
- text-[rgb(255,87,51)]
Should Not Match
- bg-primary
- bg-blue-500
Opacity Color Hack
Id
opacity-color-hack
Severity
info
Type
regex
Pattern
(?:bg|text|border)-[a-z]+-[0-9]+/[0-9]+
Message
Using opacity modifier. Ensure adequate contrast is maintained.
Fix Action
Verify contrast ratio of resulting color combination
Applies To
- *.tsx
- *.jsx
Test Cases
Should Match
- bg-blue-500/50
- text-gray-900/75
Should Not Match
- bg-blue-500
- opacity-50
Missing Semantic Color Usage
Id
missing-semantic-color
Severity
info
Type
regex
Pattern
(?:success|error|warning|danger|info).*(?:bg|text|border)-(?:green|red|yellow|blue)-[0-9]+
Message
Consider using semantic color token instead of direct color.
Fix Action
Use semantic tokens: color-success, color-danger, color-warning, color-info
Applies To
- *.tsx
- *.jsx
Test Cases
Should Match
- isError && "text-red-500"
- success ? "bg-green-100"
Should Not Match
- text-success
- bg-danger