Digital Color Spaces: HEX, RGB, HSL, OKLCH & WCAG Web Contrast Ratios
A comprehensive technical exploration of digital color models (HEX, RGB, HSL, OKLCH), perceptually uniform gamuts, and WCAG 2.1 accessible contrast ratio mathematics.
Color Picker
Validate, test, and debug this directly in your browser without sending any data to a server.
Digital Color Representation: 24-Bit TrueColor and HEX Notation
On modern digital displays, colors are created via additive color synthesis by blending Red, Green, and Blue light channels. Standard digital color models assign 8 bits (1 byte) of intensity to each channel (ranging from 0 to 255). This 24-bit TrueColor depth yields 256 × 256 × 256 = 16,777,216 distinct color combinations.
In web development, the hexadecimal format (#RRGGBB) compacts each 8-bit channel into two hexadecimal characters (00 to FF). An optional 8-bit alpha channel can be appended (#RRGGBBAA) to specify opacity, mapping cleanly to native GPU framebuffers.
RGB vs. HSL: Why Engineers Prefer Hue-Saturation-Lightness
While RGB directly mirrors hardware pixels, it is profoundly non-intuitive for human designers. If a button has background color rgb(52, 152, 219) and requires a darker hover shade, calculating the adjusted RGB triplet is complex.
HSL (Hue, Saturation, Lightness) reorganizes the color spectrum into an intuitive cylindrical coordinate system:
- Hue (0°–360°): The color family on the color wheel (0° Red, 120° Green, 240° Blue).
- Saturation (0%–100%): The intensity/purity of the color.
- Lightness (0%–100%): Luminosity from pitch black (0%) to pure white (100%).
HSL allows developers to derive systematic design systems programmatically by simply adjusting the lightness channel (hsl(204 70% 53%) -> hsl(204 70% 43%)).
The CSS Color 4 Revolution: OKLCH and Perceptual Uniformity
Despite its popularity, standard sRGB HSL suffers from a fatal flaw: it is not perceptually uniform. In HSL, pure yellow (hsl(60, 100%, 50%)) and pure blue (hsl(240, 100%, 50%)) both share an identical lightness value of 50%. Yet the human eye perceives yellow as radically brighter than blue due to the distribution of cone receptors in the retina.
CSS Color Module Level 4 introduces OKLCH (Lightness, Chroma, Hue). In OKLCH, colors that share the same lightness value look approximately equally bright regardless of hue, making accessible palettes far more predictable. Furthermore, OKLCH unlocks the wide-gamut Display P3 color space on modern OLED and Apple Retina screens.
/* Modern CSS Color Level 4 syntax */
:root {
/* Predictably accessible design tokens */
--primary-surface: oklch(0.65 0.22 260);
--primary-hover: oklch(0.55 0.22 260); /* True perceptual darkening */
--text-on-primary: oklch(0.98 0.01 260);
}WCAG 2.1 Contrast Ratio Mathematics and Standards
The Web Content Accessibility Guidelines (WCAG 2.1) require sufficient contrast between text and background surfaces to accommodate users with low vision or color vision deficiencies:
- Level AA Standard: Minimum 4.5:1 contrast ratio for normal text (< 18pt), and 3.0:1 for large text (>= 18pt or 14pt bold).
- Level AAA Standard: Minimum 7.0:1 for normal text, and 4.5:1 for large text.
The contrast ratio formula computes relative luminance L (scaled from 0 for black to 1 for white):
Contrast Ratio = (L1 + 0.05) / (L2 + 0.05) (where L1 is the lighter luminance).
Implementing Contrast Ratio Calculations in JavaScript
To audit design tokens programmatically within CI/CD or design systems, developers calculate relative luminance using the linearized sRGB formula specified by WCAG.
// Calculate WCAG relative luminance from sRGB channel (0-255)
function getLuminance(r, g, b) {
const a = [r, g, b].map(v => {
v /= 255;
return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
});
return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722;
}
// Compute contrast ratio between two RGB colors
export function getContrastRatio(rgb1, rgb2) {
const l1 = getLuminance(...rgb1);
const l2 = getLuminance(...rgb2);
const brightest = Math.max(l1, l2);
const darkest = Math.min(l1, l2);
return ((brightest + 0.05) / (darkest + 0.05)).toFixed(2);
}Color Picker
Pick and convert colors between HEX, RGB, and HSL online for free. Live color preview, WCAG contrast ratio checker, and instant CSS format conversion. No signup required.