Color Theory for Web Designers: A Practical Guide
Color is the fastest thing a visitor notices about a design and the easiest thing to get wrong. This guide covers the parts of color theory that actually matter for web and interface work: how colors relate to each other on the wheel, the harmony rules worth using, how to build a palette that survives contact with real content, and how to check that your colors are readable by everyone.
The Short Answer
- Learn the three properties of color: hue (which color), saturation (how intense), and lightness (how bright).
- Use one of three safe harmony rules for most interfaces: analogous (neighbors on the wheel), complementary (opposites), or monochromatic (one hue, varied lightness).
- Build palettes with a purpose per color: primary action, neutrals, semantic states (success, warning, error, info), and accent.
- Check text contrast against WCAG minimums: 4.5:1 for body text, 3:1 for large text (18pt and up, or 14pt bold) and UI components.
- When working in modern CSS, OKLCH gives more predictable tints and shades than HSL because its lightness scale is perceptually uniform.
1. The Three Properties of Color
Every color you will ever pick has three properties, and separating them is the single most useful color skill a designer can learn:
- Hue - the color family: red, blue, green, and everything between. The 12-hue color wheel arranges these in order: red, red-orange, orange, yellow-orange, yellow, yellow-green, green, blue-green, blue, blue-violet, violet, red-violet.
- Saturation - how vivid or muted the color is. Full saturation is the purest version of the hue; zero saturation is gray.
- Lightness (or value) - how light or dark the color is, from black through the hue to white.
Most "this palette feels off" problems are lightness problems, not hue problems. Two colors that clash often share similar lightness; separate them vertically and they usually cooperate.
Temperature is a useful shorthand: reds, oranges, and yellows read as warm (energetic, friendly, urgent); blues, greens, and violets read as cool (calm, professional, trustworthy). Warm colors advance toward the viewer and cool colors recede, which is why a warm accent on a cool background creates natural emphasis.
2. Color Harmony Rules That Actually Work
The classic harmonies are combinations of hues at fixed relationships on the wheel. For interfaces, three of them cover nearly every situation:
Analogous - two to three hues adjacent on the wheel (for example, blue, blue-green, green). Safe, calm, cohesive. The default choice for dashboards, content sites, and anything where color should not shout.
Complementary - two hues opposite on the wheel (for example, blue and orange). Maximum contrast and energy. Use the dominant color for most of the interface and the complement strictly as an accent: calls to action, highlights, badges. Equal amounts of complements vibrate and tire the eye.
Monochromatic - one hue with varied lightness and saturation. Elegant and nearly foolproof, but you must manufacture contrast through lightness steps, and it needs one clear accent for interactive elements.
Two more worth knowing for brand work: triadic (three hues evenly spaced, for example red-yellow-blue - lively, needs careful balancing) and split-complementary (a hue plus the two neighbors of its complement - contrast without the vibration of true complements).
A practical warning: harmony rules describe hue relationships only. A complementary pair where both colors sit at 40% lightness will still look muddy. Set lightness first, then apply harmony.
3. Building a Working Palette: A Repeatable Method
Start from function, not inspiration. A typical web product needs:
| Role | Typical count | Notes |
|---|---|---|
| Primary / brand | 1 hue, 3-5 lightness steps | Buttons, links, brand moments |
| Neutrals | 6-10 lightness steps | Text, borders, surfaces |
| Success | 1 hue | Green |
| Warning | 1 hue | Amber |
| Error | 1 hue | Red |
| Info | 1 hue | Blue or teal |
| Accent | 1 hue | Used sparingly for emphasis |
Step 1: Pick the primary. Choose the hue that will carry buttons, links, and brand moments. Mid-lightness, medium-high saturation is the usual range for interface primaries: vivid enough to read as interactive, dark enough to keep white text legible.
Step 2: Generate the ramp. For each hue, create steps from near-white to near-black by varying lightness in roughly even perceptual steps. The standard approach is a 9-11 step scale (like the 50-900 scales in Tailwind CSS). Even steps in OKLCH lightness are genuinely even to the eye; even steps in HSL lightness are not, because HSL's lightness model does not match human perception.
Step 3: Assign the semantics. Success, warning, error, and info colors exist so users can scan state without reading. Do not invent novel hues for these: the conventions (green, amber, red, blue) are conventions because they work instantly.
Step 4: Stress-test with real content. A palette is not done until you have checked body text on every background it will sit on, disabled states, hover states, form errors, and the palette in grayscale (to confirm lightness does the distinguishing work, not hue - important for color-blind users).
Palette checklist
- Each hue exists as a lightness ramp, not a single swatch
- The primary 600-level color passes 4.5:1 with white text (or the pairing is documented)
- The neutral ramp covers text, borders, and surfaces with distinct steps
- Semantic colors use the conventional hues users expect
- Disabled, hover, and focus states are defined for the primary
- The full palette remains distinguishable in grayscale
4. Hex, HSL, and OKLCH: Which Format to Use
Hex / RGB (#3b82f6) is the compact way to ship exact colors. Fine for final values.
HSL (hsl(217 91% 60%)) is the human-readable way to think about color: hue as degrees, saturation and lightness as percentages. Good for teaching and quick manual tweaks.
OKLCH (oklch(0.62 0.19 250)) is the modern choice for building scales. Its lightness axis is perceptually uniform: two colors with the same L value genuinely look equally bright, which makes generating tints and shades - and keeping hover states consistent across hues - much easier. It is supported in all modern browsers, and Tailwind CSS v4 uses OKLCH for its default palette.
Practical rule: think in HSL, author in OKLCH, ship in hex.
Example of why OKLCH earns its place - two buttons that need to feel equally heavy:
/* OKLCH: equal lightness = equal perceived weight */
.btn-blue { background: oklch(0.55 0.22 250); }
.btn-amber { background: oklch(0.55 0.18 80); }
The same trick in HSL requires hand-tuning each color because HSL's 55% lightness is brighter for yellow than for blue.
5. Contrast and Accessibility: The Non-Negotiable Part
The Web Content Accessibility Guidelines (WCAG) define contrast minimums that are also just good design:
- 4.5:1 - normal body text against its background (Level AA)
- 3:1 - large text (18pt and up, or 14pt bold) and meaningful UI components such as form borders (Level AA)
- 7:1 - enhanced contrast for body text (Level AAA; aim for this on long-form reading)
Common mistakes:
- Placeholder text as the only label. Placeholder gray is almost always below 4.5:1. Always use a real, visible label.
- Muted secondary text. The subtle-gray-caption habit fails contrast on white backgrounds constantly. If it is readable content, it needs 4.5:1.
- Text over images or gradients. Check the worst-case region behind the text, not the average. Add a scrim (a translucent dark overlay) when the background is busy.
- Color-only meaning. Never communicate state with color alone. Error messages need text or an icon alongside the red.
Our contrast checker tool computes WCAG contrast ratios for any foreground/background pair, and the accessible color systems guide covers building full palettes that stay compliant. For the broader compliance picture, see the WCAG 2.2 accessibility guide.
6. Applying Color Consistently: Tokens
Hard-coded hex values scattered across a codebase are how palettes decay. Design tokens - named, centralized color definitions - are how they survive:
:root {
--color-primary-600: oklch(0.55 0.22 250);
--color-primary-700: oklch(0.48 0.21 250);
--color-text: oklch(0.25 0.01 250);
--color-surface: oklch(0.98 0.005 250);
}
Components reference tokens, never raw values. When the brand blue changes, you change one line. The guide to building a design system from scratch covers token architecture in depth.
7. Common Color Mistakes (and the Fix)
| Mistake | Why it fails | Fix |
|---|---|---|
| Pure black text (#000) on pure white | Harsh, causes eye fatigue in long reads | Use a very dark neutral such as #1a1a1a |
| Too many hues | No hierarchy; everything competes | Cap the palette: 1 primary, 1 accent, neutrals, 4 semantics |
| Saturation everywhere | Vibrant backgrounds fight with content | Keep surfaces neutral; reserve saturation for actions and accents |
| Hover states that shift hue | Feels inconsistent | Shift lightness only, keep hue fixed |
| Dark mode as inverted light mode | Pure inverted colors look neon on dark | Rebuild the ramp: dark surfaces, desaturated accents, stronger text contrast |
Frequently Asked Questions
How many colors should a website use? For most sites: one primary hue, one accent, a neutral ramp, and four semantic colors (success, warning, error, info). Add hues only when a new color carries new meaning.
What is the 60-30-10 rule? A ratio borrowed from interior design: roughly 60% dominant neutral background, 30% secondary surfaces, 10% accent. It is a starting point, not a law.
Should I use OKLCH or HSL? Both are fine, but OKLCH is the better default for generating scales because its lightness is perceptually uniform. Browser support is universal in modern browsers.
How do I pick brand colors from scratch? Start with the emotion and audience (see temperature, above), pick one memorable primary hue, then build the functional palette around it using the method in section 3. Test the primary as a button, a link, and a logo mark before committing.
Why does my palette look good in the picker but bad in the design? Usually a lightness problem: the hues are harmonious but sit at similar lightness levels, so nothing has hierarchy. Squint at the design - if it turns to mush, separate the lightness values.
Continue Reading
- Accessible Color Systems Guide - building palettes that pass WCAG from the start
- Chart Color Accessibility Checklist - color choices for data visualization
- Building a Design System from Scratch - tokenizing your palette