Introduction
Understanding color models is fundamental to both digital and print design. Whether you’re designing for web, mobile, or print, knowing how colors are represented and converted between different models ensures consistent results across all media.
This comprehensive guide covers the major color models - RGB, CMYK, HSL, and others - explaining how they work, when to use each, and practical conversion techniques. Whether you’re a developer implementing color pickers or a designer creating brand materials, this guide provides the knowledge you need.
The key insight is that different color models suit different purposes. RGB works for light-emitting displays, CMYK for subtractive printing, and HSL for intuitive human color manipulation. Understanding these differences prevents costly mistakes in production.
Understanding Color Models
What is a Color Model?
A color model is a system for representing colors numerically. Different models use different approaches to define colors:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Color Model Comparison โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ RGB (Additive) โ โ
โ โ โข Used for: Screens, displays, web โ โ
โ โ โข Based on: Light emission โ โ
โ โ โข Colors created by: Combining red, green, blue light โ โ
โ โ โข Example: RGB(255, 0, 0) = Pure red โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ CMYK (Subtractive) โ โ
โ โ โข Used for: Print, physical media โ โ
โ โ โข Based on: Light absorption โ โ
โ โ โข Colors created by: Absorbing ink on white paper โ โ
โ โ โข Example: CMYK(100%, 0%, 0%, 0%) = Pure cyan โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ HSL (Human-Friendly) โ โ
โ โ โข Used for: Programming, color manipulation โ โ
โ โ โข Based on: Human perception โ โ
โ โ โข Colors created by: Adjusting hue, saturation, lightnessโ โ
โ โ โข Example: hsl(0, 100%, 50%) = Pure red โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
RGB Color Model
How RGB Works
RGB is an additive color model used by light-emitting devices like screens, monitors, and televisions. Colors are created by combining varying intensities of red, green, and blue light.
# RGB Color representation
class RGB:
"""Represents a color in RGB space."""
def __init__(self, r: int, g: int, b: int, a: float = 1.0):
# Clamp values
self.r = max(0, min(255, r))
self.g = max(0, min(255, g))
self.b = max(0, min(255, b))
self.a = max(0, min(1, a))
def to_hex(self) -> str:
"""Convert to hex color."""
return f"#{self.r:02x}{self.g:02x}{self.b:02x}"
def to_rgba_string(self) -> str:
"""Convert to RGBA string for CSS."""
return f"rgba({self.r}, {self.g}, {self.b}, {self.a})"
def to_hsl(self) -> 'HSL':
"""Convert RGB to HSL."""
r, g, b = self.r / 255, self.g / 255, self.b / 255
max_c = max(r, g, b)
min_c = min(r, g, b)
l = (max_c + min_c) / 2
if max_c == min_c:
h = s = 0
else:
d = max_c - min_c
s = d / (2 - max_c - min_c) if l > 0.5 else d / (max_c + min_c)
if max_c == r:
h = ((g - b) / d + (6 if g < b else 0)) / 6
elif max_c == g:
h = ((b - r) / d + 2) / 6
else:
h = ((r - g) / d + 4) / 6
return HSL(int(h * 360), int(s * 100), int(l * 100), self.a)
def __repr__(self):
return f"RGB({self.r}, {self.g}, {self.b}, {self.a})"
# Common colors in RGB
RED = RGB(255, 0, 0)
GREEN = RGB(0, 255, 0)
BLUE = RGB(0, 0, 255)
WHITE = RGB(255, 255, 255)
BLACK = RGB(0, 0, 0)
YELLOW = RGB(255, 255, 0)
CYAN = RGB(0, 255, 255)
MAGENTA = RGB(255, 0, 255)
# Color mixing
def mix_colors(c1: RGB, c2: RGB, weight: float = 0.5) -> RGB:
"""Mix two colors."""
w1 = weight
w2 = 1 - weight
return RGB(
int(c1.r * w1 + c2.r * w2),
int(c1.g * w1 + c2.g * w2),
int(c1.b * w1 + c2.b * w2)
)
RGB in CSS/JavaScript
// RGB and RGBA in CSS
const colors = {
red: 'rgb(255, 0, 0)',
green: 'rgb(0, 255, 0)',
blue: 'rgb(0, 0, 255)',
transparent: 'rgba(255, 0, 0, 0.5)',
hsla: 'hsla(120, 100%, 50%, 0.5)'
};
// JavaScript color manipulation
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;
}
function rgbToHex(r, g, b) {
return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
}
// HSL to RGB conversion
function hslToRgb(h, s, l) {
s /= 100;
l /= 100;
const c = (1 - Math.abs(2 * l - 1)) * s;
const x = c * (1 - Math.abs((h / 60) % 2 - 1));
const m = l - c / 2;
let r, g, b;
if (h < 60) [r, g, b] = [c, x, 0];
else if (h < 120) [r, g, b] = [x, c, 0];
else if (h < 180) [r, g, b] = [0, c, x];
else if (h < 240) [r, g, b] = [0, x, c];
else if (h < 300) [r, g, b] = [x, 0, c];
else [r, g, b] = [c, 0, x];
return {
r: Math.round((r + m) * 255),
g: Math.round((g + m) * 255),
b: Math.round((b + m) * 255)
};
}
Alpha Channel
The alpha channel controls opacity:
# RGBA - Adding transparency
transparent_red = RGB(255, 0, 0, 0.5) # 50% transparent
print(transparent_red.to_rgba_string()) # rgba(255, 0, 0, 0.5)
# CSS color with alpha
css_with_alpha = "rgba(255, 0, 0, 0.5)"
hex_with_alpha = "#FF000080" # 8-digit hex (last 2 digits = alpha)
CMYK Color Model
How CMYK Works
CMYK is a subtractive color model used in print. Colors are created by absorbing (subtracting) certain wavelengths of light and reflecting others. The name comes from Cyan, Magenta, Yellow, and Key (black).
class CMYK:
"""Represents a color in CMYK space."""
def __init__(self, c: float, m: float, y: float, k: float):
# CMYK values are percentages (0-100)
self.c = max(0, min(100, c))
self.m = max(0, min(100, m))
self.y = max(0, min(100, y))
self.k = max(0, min(100, k))
def to_rgb(self) -> RGB:
"""Convert CMYK to RGB."""
if self.c == 0 and self.m == 0 and self.y == 0 and self.k == 0:
return RGB(255, 255, 255)
r = 255 * (1 - self.c / 100) * (1 - self.k / 100)
g = 255 * (1 - self.m / 100) * (1 - self.k / 100)
b = 255 * (1 - self.y / 100) * (1 - self.k / 100)
return RGB(int(r), int(g), int(b))
@classmethod
def from_rgb(cls, rgb: RGB) -> 'CMYK':
"""Create CMYK from RGB."""
r, g, b = rgb.r / 255, rgb.g / 255, rgb.b / 255
k = 1 - max(r, g, b)
if k == 1:
return cls(0, 0, 0, 100)
c = (1 - r - k) / (1 - k) * 100
m = (1 - g - k) / (1 - k) * 100
y = (1 - b - k) / (1 - k) * 100
return cls(c, m, y, k * 100)
def __repr__(self):
return f"CMYK({self.c:.0f}%, {self.m:.0f}%, {self.y:.0f}%, {self.k:.0f}%)"
# Example conversions
pure_cyan = CMYK(100, 0, 0, 0)
print(pure_cyan.to_rgb()) # RGB(0, 255, 255)
# From RGB to CMYK
red = RGB(255, 0, 0)
cmyk_red = CMYK.from_rgb(red)
print(cmyk_red) # CMYK(0%, 100%, 100%, 0%)
RGB to CMYK Conversion
def rgb_to_cmyk(r, g, b):
"""Convert RGB to CMYK."""
# Normalize RGB values
r_norm = r / 255
g_norm = g / 255
b_norm = b / 255
# Calculate K (black)
k = 1 - max(r_norm, g_norm, b_norm)
if k == 1:
return (0, 0, 0, 100)
# Calculate CMY
c = (1 - r_norm - k) / (1 - k) * 100
m = (1 - g_norm - k) / (1 - k) * 100
y = (1 - b_norm - k) / (1 - k) * 100
return (c, m, y, k * 100)
# Practical example
r, g, b = 100, 150, 200
c, m, y, k = rgb_to_cmyk(r, g, b)
print(f"RGB({r}, {g}, {b}) = CMYK({c:.0f}%, {m:.0f}%, {y:.0f}%, {k:.0f}%)")
Why CMYK Matters for Print
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ RGB to CMYK: Key Considerations โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โ
โ Problem: RGB colors may look different when printed โ
โ โ
โ Reasons: โ
โ โข RGB is additive (light), CMYK is subtractive (ink) โ
โ โข Color gamut: RGB has wider range of printable colors โ
โ โข Paper affects final appearance โ
โ โข Ink limitations (metallic, fluorescent colors hard to print) โ
โ โ
โ Solutions: โ
โ โข Use CMYK from the start for print projects โ
โ โข Use color profiles (US Web Coated SWOP v2) โ
โ โข Proof colors before large print runs โ
โ โข Account for dot gain and absorption โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
HSL Color Model
How HSL Works
HSL (Hue, Saturation, Lightness) is designed to be more intuitive for humans:
class HSL:
"""Represents a color in HSL space."""
def __init__(self, h: int, s: int, l: int, a: float = 1.0):
# Hue: 0-360, Saturation: 0-100, Lightness: 0-100
self.h = h % 360
self.s = max(0, min(100, s))
self.l = max(0, min(100, l))
self.a = max(0, min(1, a))
def to_rgb(self) -> RGB:
"""Convert HSL to RGB."""
h, s, l = self.h / 360, self.s / 100, self.l / 100
if s == 0:
gray = int(l * 255)
return RGB(gray, gray, gray, self.a)
q = l * (1 + s) if l < 0.5 else l + s - l * s
p = 2 * l - q
r = self._hue_to_rgb(p, q, h + 1/3)
g = self._hue_to_rgb(p, q, h)
b = self._hue_to_rgb(p, q, h - 1/3)
return RGB(int(r * 255), int(g * 255), int(b * 255), self.a)
def _hue_to_rgb(self, p, q, t):
if t < 0: t += 1
if t > 1: t -= 1
if t < 1/6: return p + (q - p) * 6 * t
if t < 1/2: return q
if t < 2/3: return p + (q - p) * (2/3 - t) * 6
return p
def __repr__(self):
return f"HSL({self.h}, {self.s}%, {self.l}%)"
# HSL examples
red = HSL(0, 100, 50) # Pure red
green = HSL(120, 100, 50) # Pure green
blue = HSL(240, 100, 50) # Pure blue
gray = HSL(0, 0, 50) # Neutral gray
# Lightness variations
for l in [10, 30, 50, 70, 90]:
color = HSL(200, 80, l)
rgb = color.to_rgb()
print(f"HSL(200, 80%, {l}%) = {rgb.to_hex()}")
Practical HSL Applications
// Generate color palette from base hue
function generatePalette(baseHue, count = 5) {
const palette = [];
for (let i = 0; i < count; i++) {
// Vary lightness and saturation
const hue = (baseHue + i * 30) % 360;
const saturation = 70 + Math.random() * 20;
const lightness = 40 + Math.random() * 20;
palette.push(`hsl(${hue}, ${saturation}%, ${lightness}%)`);
}
return palette;
}
// Darken/lighten colors
function adjustLightness(hsl, amount) {
const [h, s, l] = hsl.match(/\d+/g).map(Number);
const newL = Math.max(0, Math.min(100, l + amount));
return `hsl(${h}, ${s}%, ${newL}%)`;
}
// Color picker integration
function getColorAtAngle(angle, radius, center) {
const hue = (angle * 180 / Math.PI + 90) % 360;
return `hsl(${hue}, 70%, 50%)`;
}
Color Spaces Beyond RGB and CMYK
Additional Color Models
| Model | Use Case | Channels |
|---|---|---|
| HSV/HSB | Image editing | Hue, Saturation, Value/Brightness |
| LAB | Color correction | Lightness, A (green-red), B (blue-yellow) |
| XYZ | Color science | X, Y, Z (tristimulus values) |
| YCbCr | Video/TV | Luminance, Chrominance blue, Chrominance red |
# HSV to RGB conversion
def hsv_to_rgb(h, s, v):
"""Convert HSV to RGB."""
s /= 100
v /= 100
c = v * s
x = c * (1 - abs((h / 60) % 2 - 1))
m = v - c
if h < 60: r, g, b = c, x, 0
elif h < 120: r, g, b = x, c, 0
elif h < 180: r, g, b = 0, c, x
elif h < 240: r, g, b = 0, x, c
elif h < 300: r, g, b = x, 0, c
else: r, g, b = c, 0, x
return (int((r + m) * 255),
int((g + m) * 255),
int((b + m) * 255))
Color Theory for Design
Color Relationships
# Color relationship calculations
def complementary(hsl: HSL) -> HSL:
"""Get complementary color."""
return HSL((hsl.h + 180) % 360, hsl.s, hsl.l)
def triadic(hsl: HSL) -> tuple:
"""Get triadic colors."""
return (
hsl,
HSL((hsl.h + 120) % 360, hsl.s, hsl.l),
HSL((hsl.h + 240) % 360, hsl.s, hsl.l)
)
def analogous(hsl: HSL) -> tuple:
"""Get analogous colors."""
return (
HSL((hsl.h - 30) % 360, hsl.s, hsl.l),
hsl,
HSL((hsl.h + 30) % 360, hsl.s, hsl.l)
)
def split_complementary(hsl: HSL) -> tuple:
"""Get split complementary colors."""
return (
hsl,
HSL((hsl.h + 150) % 360, hsl.s, hsl.l),
HSL((hsl.h + 210) % 360, hsl.s, hsl.l)
)
Building Color Palettes
def generate_palette(base: HSL, style: str = 'analogous') -> list:
"""Generate color palette based on strategy."""
if style == 'monochromatic':
return [Hsl(base.h, base.s, l) for l in [20, 40, 60, 80, 100]]
elif style == 'complementary':
comp = complementary(base)
return [base, comp, HSL(base.h, base.s, 70),
HSL(comp.h, comp.s, 70)]
elif style == 'triadic':
colors = triadic(base)
return list(colors) + [HSL(c.h, c.s, 70) for c in colors[:2]]
elif style == 'analogous':
return [
HSL((base.h - 30 + i * 15) % 360, base.s, base.l)
for i in range(-2, 3)
]
return [base]
Best Practices
| Practice | Implementation |
|---|---|
| Use RGB for web | Start with RGB for digital projects |
| Convert for print | Switch to CMYK early for print |
| Use HSL for manipulation | Easier to reason about than RGB |
| Test across media | Preview colors in both models |
| Use color profiles | Maintain consistency |
| Consider accessibility | Check contrast ratios |
Conclusion
Understanding color models is essential for any design work. Whether you’re building websites, creating print materials, or developing applications, knowing how colors are represented and converted prevents costly mistakes.
Key takeaways:
- RGB is for digital screens (additive light)
- CMYK is for print (subtractive ink)
- HSL is for intuitive color manipulation
- Convert early - Work in the right model for your output
- Test thoroughly - Colors appear differently across media
By mastering these color models and their conversions, you’ll create consistent, professional designs across all media.
Comments