What Are Color Models?
Color models are mathematical systems that describe colors as tuples of numbers. Rather than saying "that warm orange-red," a designer can communicate #FF4500, rgb(255, 69, 0), or hsl(16, 100%, 50%)—unambiguous, reproducible, and transferable across tools, teams, and media.
The need for precise color description is ancient. In 1666, Isaac Newton passed white sunlight through a glass prism and produced a rainbow spectrum, demonstrating that "white" light contains all visible colors. But a spectrum alone doesn't tell us how to mix or specify a color systematically.
The first practical color order system came from Albert H. Munsell in 1905. He arranged colors on three axes—Hue, Value (lightness), and Chroma (saturation)—in a perceptual tree-like structure. His system was the direct ancestor of HSL and HSV.
The modern scientific foundation arrived in 1931 when the International Commission on Illumination (CIE) published the CIE 1931 XYZ color space—the first mathematically rigorous, device-independent description of human color perception, derived from experiments on human observers matching colored lights. Every color model used in computing ultimately traces back to this standard.
The digital era brought hardware-driven models. CRT monitors mix red, green, and blue phosphor dots (RGB). Inkjet printers spray cyan, magenta, yellow, and black inks (CMYK). Each medium needed its own model, and the need to convert between them gave rise to tools like the one you're using now.
RGB — The Language of Screens
RGB (Red, Green, Blue) is an additive color model. Adding light increases brightness; all three channels at maximum (255, 255, 255) produce white; all at zero produce black. This matches how monitors, TVs, and smartphone screens work—millions of tiny pixels, each a cluster of red, green, and blue sub-pixels emitting light at varying intensities.
Each channel ranges from 0 to 255 (8 bits, 256 levels). That gives 256³ = 16,777,216 distinct colors—commonly called "24-bit true color." For HDR displays, 10-bit per channel (1024 levels) is becoming standard.
RGB(255, 0, 0) → pure red
RGB(0, 255, 0) → pure green
RGB(0, 0, 255) → pure blue
RGB(255, 255, 0) → yellow (red + green)
RGB(0, 0, 0) → black
RGB(255,255,255) → white
RGB is the native language of CSS, canvas APIs, WebGL shaders, and image processing libraries. Its weakness is that it's not perceptually intuitive—if you want a slightly lighter blue, you don't know which numbers to tweak.
HEX — The Web's Compact Color Notation
HEX is simply RGB encoded in hexadecimal notation. Each channel (0–255 decimal) becomes a two-digit hex string (00–FF). The full color is prefixed with #.
255 decimal = FF hex
128 decimal = 80 hex
0 decimal = 00 hex
So rgb(255, 128, 0) becomes #FF8000. The format is compact, copy-pasteable, and ubiquitous in HTML, CSS, and design tool swatches.
A shorthand form exists when both digits of each channel are identical: #FF8800 → #F80. CSS also supports an 8-digit form #RRGGBBAA for colors with alpha transparency (e.g., #FF800080 = 50% transparent orange).
HEX is convenient for developers but offers no more semantic clarity than RGB—tweaking a value is still largely trial-and-error without a color picker.
HSL — Designed for Humans
HSL (Hue, Saturation, Lightness) reorganizes the color space in a way that maps to human intuition:
- Hue (H): The color wheel angle, 0°–360°. Red = 0°, Yellow = 60°, Green = 120°, Cyan = 180°, Blue = 240°, Magenta = 300°, back to Red = 360°.
- Saturation (S): 0%–100%. At 0% all colors become gray; at 100% the color is fully vivid.
- Lightness (L): 0%–100%. 0% is always black; 100% is always white; 50% is the "pure" hue.
This makes design operations natural: "make this color 20% lighter" is just L: 50% → 70%. "Desaturate by half" is S: 80% → 40%. CSS hsl() is now widely used in design systems because it allows component-level color adjustments with arithmetic.
HSL is a cylindrical remapping of the RGB cube. It's computationally cheap to convert but has a perceptual weakness: hsl(60, 100%, 50%) (yellow) looks much brighter than hsl(240, 100%, 50%) (blue) even though both have the same L value of 50%. For perceptual uniformity, use Lab or oklch.
HSV / HSB — Photoshop's Model
HSV (Hue, Saturation, Value) — also called HSB (Hue, Saturation, Brightness) — is structurally similar to HSL but replaces Lightness with Value:
- Value (V): 0%–100%. At 0%, the color is always black regardless of H and S. At 100%, the color is at full brightness (but not necessarily white).
The practical difference: in HSL, a pure color sits at L=50%; in HSV, a pure color sits at V=100%, S=100%. Increasing L above 50% in HSL adds white (tinting); HSV has no native tint—you lower S to add white.
Adobe Photoshop, Illustrator, and most professional color pickers use HSV/HSB because its "full brightness" model feels natural when picking vivid colors. Designers often prefer HSV for palette creation, while developers prefer HSL for CSS manipulations.
CMYK — The Print Model
CMYK (Cyan, Magenta, Yellow, Key/Black) is a subtractive color model. Unlike additive RGB (adding light creates white), subtractive models work with ink on paper—each ink absorbs (subtracts) certain wavelengths, and the reflected light is what we see.
- Cyan absorbs red; reflects blue+green
- Magenta absorbs green; reflects red+blue
- Yellow absorbs blue; reflects red+green
- Key (Black) improves shadow depth and saves ink cost (CMY mixed rarely produces a true black)
Each channel is expressed as a percentage 0–100%. CMYK is the standard for offset printing, packaging, magazines, and anything that ends up as physical ink on paper.
A critical warning: RGB and CMYK are not fully interchangeable. Many vibrant RGB colors (neon greens, electric blues) fall outside the CMYK gamut and will print as duller approximations. Always proof in CMYK before sending files to press.
The RGB→CMYK conversion is an approximation without a color profile:
K = 1 - max(R, G, B)
C = (1 - R - K) / (1 - K)
M = (1 - G - K) / (1 - K)
Y = (1 - B - K) / (1 - K)
(where R, G, B are normalized 0–1)
CIE L*a*b* — Perceptual Uniformity
Lab (or CIELAB) is a device-independent color space designed so that equal numerical distances correspond to equal perceived color differences. It was created by the CIE in 1976 to address the perceptual non-uniformity of earlier models.
- L* : Lightness, 0 (black) to 100 (white)
- a* : Green (negative) to Red (positive), roughly −128 to +127
- b* : Blue (negative) to Yellow (positive), roughly −128 to +127
Lab is the gold standard for color science, image editing (Photoshop's Lab mode), and color difference calculations (ΔE). A ΔE < 1 is imperceptible to the human eye; ΔE < 3 is acceptable for most print work.
Lab's coordinate system is derived from the CIE XYZ space using a cube-root function that models human eye response. It's the basis for modern CSS oklch(), which repackages Lab in polar coordinates (Lightness, Chroma, Hue) for easier use.
RGBA and HSLA — Adding Transparency
Both RGB and HSL support an alpha channel — a fourth value from 0 (fully transparent) to 1 (fully opaque) — giving RGBA and HSLA.
rgba(255, 99, 71, 0.5) /* tomato at 50% opacity */
hsla(9, 100%, 64%, 0.7) /* same color, 70% opaque */
Alpha compositing follows the Porter-Duff "over" operation: the final displayed color blends the layer's color with what's behind it according to the alpha value. CSS also accepts a slash syntax in modern rgb() and hsl() notation: rgb(255 99 71 / 50%).
Mathematical Conversion Formulas
RGB ↔ HEX
// RGB to HEX conversion
function rgbToHex(r, g, b) {
return '#' + [r, g, b]
.map(v => Math.round(v).toString(16).padStart(2, '0'))
.join('');
}
// HEX to RGB
function hexToRgb(hex) {
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result ? {
r: parseInt(result[1], 16),
g: parseInt(result[2], 16),
b: parseInt(result[3], 16)
} : null;
}
RGB ↔ HSL
// RGB to HSL
function rgbToHsl(r, g, b) {
r /= 255; g /= 255; b /= 255;
const max = Math.max(r, g, b), min = Math.min(r, g, b);
let h, s, l = (max + min) / 2;
if (max === min) {
h = s = 0; // achromatic
} else {
const d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch (max) {
case r: h = ((g - b) / d + (g < b ? 6 : 0)) / 6; break;
case g: h = ((b - r) / d + 2) / 6; break;
case b: h = ((r - g) / d + 4) / 6; break;
}
}
return { h: Math.round(h * 360), s: Math.round(s * 100), l: Math.round(l * 100) };
}
RGB ↔ HSV
function rgbToHsv(r, g, b) {
r /= 255; g /= 255; b /= 255;
const max = Math.max(r, g, b), min = Math.min(r, g, b);
const d = max - min;
let h, s = max === 0 ? 0 : d / max, v = max;
if (max === min) {
h = 0;
} else {
switch (max) {
case r: h = ((g - b) / d + (g < b ? 6 : 0)) / 6; break;
case g: h = ((b - r) / d + 2) / 6; break;
case b: h = ((r - g) / d + 4) / 6; break;
}
}
return { h: Math.round(h * 360), s: Math.round(s * 100), v: Math.round(v * 100) };
}
RGB → CMYK (Approximation)
function rgbToCmyk(r, g, b) {
r /= 255; g /= 255; b /= 255;
const k = 1 - Math.max(r, g, b);
if (k === 1) return { c: 0, m: 0, y: 0, k: 100 };
return {
c: Math.round(((1 - r - k) / (1 - k)) * 100),
m: Math.round(((1 - g - k) / (1 - k)) * 100),
y: Math.round(((1 - b - k) / (1 - k)) * 100),
k: Math.round(k * 100)
};
}
Color Spaces and Profiles
A color space defines which subset of all visible colors a device or file can represent. The most important ones:
| Color Space | Gamut Coverage | Use Case |
|---|---|---|
| sRGB | ~35% of visible | Web, standard monitors, JPEG |
| Adobe RGB | ~50% of visible | Professional photography, print |
| Display P3 | ~45% of visible | iPhone, Mac, modern displays |
| ProPhoto RGB | ~90% of visible | RAW photo editing |
| Rec. 2020 | ~75% of visible | HDR video, 4K broadcasting |
Web designers overwhelmingly work in sRGB, which is the assumed color space of CSS, PNG, and JPEG. However, Apple's Safari and Chrome now support the color() CSS function with display-p3 for wide-gamut displays, and the oklch() function can reference colors outside sRGB entirely.
Color profiles (ICC profiles) are the data files that tell software exactly how to map color numbers to real-world light. When you export an image "with embedded profile," the ICC profile travels with the file, ensuring consistent rendering across devices.
CSS Color Usage
CSS has evolved from basic hex values to a rich color ecosystem:
/* Modern CSS color usage */
:root {
--primary: #3B82F6;
--primary-hsl: hsl(217, 91%, 60%);
/* oklch for P3 wide gamut */
--accent: oklch(70% 0.2 250);
}
/* WCAG contrast check helper */
.text-accessible {
color: #1a1a1a; /* contrast 16.1:1 on white — AAA */
background: #ffffff;
}
Named colors: CSS defines 140 named colors, from aliceblue to yellowgreen. They're readable but inflexible for systematic design.
Modern functions:
rgb(255 99 71)— space-separated modern syntaxhsl(9deg 100% 64%)— readable, adjustableoklch(70% 0.2 250)— perceptually uniform, wide-gamut capablecolor(display-p3 1 0.389 0.279)— explicit wide-gamut
CSS custom properties (variables) are the cornerstone of modern theming:
:root {
--color-primary-500: hsl(217, 91%, 60%);
--color-primary-600: hsl(217, 91%, 50%);
--color-primary-700: hsl(217, 91%, 40%);
}
With HSL-based variables, generating a full shade scale from a single hue is straightforward—just adjust the L value arithmetically.
Accessibility and Contrast Ratios
The WCAG (Web Content Accessibility Guidelines) define contrast ratio requirements for readable text:
- Level AA: 4.5:1 for normal text, 3:1 for large text (18pt or 14pt bold)
- Level AAA: 7:1 for normal text, 4.5:1 for large text
Contrast ratio is calculated from relative luminance:
Contrast = (L1 + 0.05) / (L2 + 0.05)
where L1 is the lighter luminance and L2 is the darker.
Relative luminance converts gamma-compressed sRGB to linear light:
function relativeLuminance(r, g, b) {
const [rs, gs, bs] = [r, g, b].map(v => {
v /= 255;
return v <= 0.04045 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
});
return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs;
}
Common safe combinations: black (#000000) on white (#ffffff) = 21:1 (perfect AAA); #767676 gray on white = exactly 4.5:1 (AA pass).
How Design Tools Handle Colors
Figma: Stores colors as RGB internally. The color picker exposes HEX, RGB, HSL, HSB, and CSS notation. Design tokens (variables) can be published to code via Figma's Variables API, exporting as CSS custom properties or JSON.
Sketch: Uses RGB with named swatches and shared color libraries. Supports CMYK export hints for print deliverables. Integration with plugins like Stark adds WCAG contrast checking.
Adobe XD / Illustrator / Photoshop: Adobe tools natively support CMYK, Lab, and color-profile-aware workflows. Photoshop's color picker defaults to HSB (HSV). Illustrator's Recolor Artwork uses HSB globaly for palette harmony operations.
In all tools, a core workflow is: pick a color in HSL/HSV for visual intuition, export in HEX/RGB for web code, and confirm CMYK equivalents before sending to print.
Use Cases: Brand, Tokens, and Cross-Medium Consistency
Brand guidelines define the canonical set of colors for an organization. A well-specified brand color might read:
Pantone 286 C
CMYK: 100 / 72 / 0 / 18
RGB: 0 / 84 / 166
HEX: #0054A6
This multi-format specification ensures that the blue looks correct whether it's silk-screened on a t-shirt, printed in a brochure, or displayed on a website.
Design tokens are named variables that map semantic roles to color values. A token system might look like:
{
"color": {
"brand": { "primary": { "value": "#0054A6" } },
"feedback": {
"error": { "value": "#D32F2F" },
"success": { "value": "#388E3C" },
"warning": { "value": "#F57C00" }
}
}
}
Tools like Style Dictionary then transform tokens into platform-specific files: CSS variables for web, Swift constants for iOS, XML resources for Android.
Comparison: HSL vs HSV, sRGB vs Wide Gamut
HSL vs HSV:
- Both derive from RGB; neither is perceptually uniform
- HSL's pure hue is at L=50%; HSV's pure hue is at V=100%, S=100%
- In HSL, raising L above 50% adds white (tint); there's no HSL equivalent to raising V in HSV
- HSV is better for a color picker UI (full-saturation grid); HSL is better for CSS manipulation
- For true perceptual uniformity, use oklch/Lab instead of either
sRGB vs Wide Gamut:
- sRGB covers about 35% of the CIE 1931 horseshoe—sufficient for most web work
- Display P3 covers ~45%, enabling more vivid greens and reds visible on modern Apple/Samsung screens
- Using wide-gamut colors on standard screens causes clipping—colors are clamped to the nearest sRGB value
- CSS
@media (color-gamut: p3)lets you progressively enhance with P3 colors
Best Practices for Color Management
- Define your color space early. Use sRGB as your default; add P3 enhancements progressively.
- Use HSL for CSS variables to enable mathematical shade generation and easy theming.
- Always specify colors in multiple formats for brand guidelines (Pantone, CMYK, RGB, HEX).
- Check WCAG contrast for every text-background combination before shipping.
- Embed ICC profiles in exported images to preserve intent across devices.
- Prefer semantic tokens over raw hex in design systems—
--color-interactive-hoverover#0066CC. - Test in dark mode: HSL-based variables make dark mode theming far easier than hex swaps.
- Don't assume CMYK from RGB: Always involve a print professional to proof critical color assets.
- Use oklch for modern CSS when targeting vivid, wide-gamut colors with perceptual uniformity.
- Document color decisions: Record why colors were chosen—accessibility rationale, brand history, emotional intent.
Frequently Asked Questions
Q1: What's the difference between HEX and RGB?
They represent the same information differently. #FF8000 and rgb(255, 128, 0) are identical colors—HEX just uses hexadecimal notation. HEX is more compact; RGB is more readable for large numbers.
Q2: Why does my RGB color look different in print? Screens are additive (light); print is subtractive (ink). Many vivid screen colors—especially electric blues and neon greens—cannot be reproduced with ink, so they get "gamut-mapped" to the nearest printable equivalent, appearing duller.
Q3: When should I use HSL vs HSV? Use HSL when writing CSS or building design tokens—it integrates naturally with modern CSS. Use HSV when working in Photoshop/Illustrator color pickers or building your own color picker UI component.
Q4: What is oklch and why is it better than HSL?
oklch is a CSS color function using the Oklab perceptual color space. Unlike HSL, it maintains consistent perceived lightness across hues—a yellow and a blue at the same oklch lightness actually look the same brightness. It also supports wide-gamut Display P3 colors.
Q5: How do I check if two colors have enough contrast?
Calculate relative luminance for each color, then apply: (lighter + 0.05) / (darker + 0.05). The result must be ≥ 4.5 for WCAG AA. Our color converter includes a built-in contrast checker.
Q6: Is the RGB→CMYK conversion in this tool accurate? The mathematical conversion is a device-independent approximation. For professional print work, accurate CMYK requires ICC color profiles specific to your printer and paper—the conversion varies significantly between press types. Use the tool for estimates; always proof with your print vendor.
Q7: Can I use CSS oklch() today?
Yes—oklch() has full support in Chrome 111+, Firefox 113+, Safari 16.4+, and Edge 111+. For older browsers, provide a fallback: color: hsl(250, 80%, 55%); color: oklch(55% 0.18 250);. The browser uses the last supported value.