Color Converter Guide: HEX, RGB, HSL, and Beyond for Developers
Colors in web development come in many formats. Learn to convert between HEX, RGB, HSL and understand when to use each format.
Understanding Color Formats
Web developers work with colors in multiple formats. Each has its strengths and ideal use cases. Let's master them all.
Color Format Overview
HEX (Hexadecimal)
The most common format in web development:
/* 6-digit HEX */
color: #FF5733;
/* 3-digit shorthand (when digits repeat) */
color: #F00; /* Same as #FF0000 */
/* 8-digit with alpha */
color: #FF573380; /* 50% opacity */Structure: #RRGGBB or #RRGGBBAA
- RR: Red (00-FF)
- GG: Green (00-FF)
- BB: Blue (00-FF)
- AA: Alpha (00-FF)
RGB/RGBA
Red, Green, Blue values (0-255):
/* RGB */
color: rgb(255, 87, 51);
/* RGBA with opacity */
color: rgba(255, 87, 51, 0.5);
/* Modern syntax */
color: rgb(255 87 51);
color: rgb(255 87 51 / 50%);HSL/HSLA
Hue, Saturation, Lightness:
/* HSL */
color: hsl(11, 100%, 60%);
/* HSLA with opacity */
color: hsla(11, 100%, 60%, 0.5);
/* Modern syntax */
color: hsl(11 100% 60% / 50%);Structure:
- Hue: 0-360 (color wheel degree)
- Saturation: 0%-100% (gray to vivid)
- Lightness: 0%-100% (black to white)
HSB/HSV
Hue, Saturation, Brightness (used in design tools):
H: 11°
S: 80%
B: 100%Note: CSS doesn't support HSB natively. Convert to HSL for web use.
Color Conversion Formulas
HEX to RGB
function hexToRgb(hex) {
// Remove # if present
hex = hex.replace('#', '');
// Handle 3-digit shorthand
if (hex.length === 3) {
hex = hex.split('').map(c => c + c).join('');
}
const r = parseInt(hex.substring(0, 2), 16);
const g = parseInt(hex.substring(2, 4), 16);
const b = parseInt(hex.substring(4, 6), 16);
return { r, g, b };
}
// Usage
hexToRgb('#FF5733'); // { r: 255, g: 87, b: 51 }RGB to HEX
function rgbToHex(r, g, b) {
const toHex = n => n.toString(16).padStart(2, '0');
return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
}
// Usage
rgbToHex(255, 87, 51); // "#ff5733"RGB to HSL
function rgbToHsl(r, g, b) {
r /= 255;
g /= 255;
b /= 255;
const max = Math.max(r, g, b);
const min = Math.min(r, g, b);
const l = (max + min) / 2;
if (max === min) {
return { h: 0, s: 0, l: Math.round(l * 100) };
}
const d = max - min;
const s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
let h;
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)
};
}
// Usage
rgbToHsl(255, 87, 51); // { h: 11, s: 100, l: 60 }HSL to RGB
function hslToRgb(h, s, l) {
h /= 360;
s /= 100;
l /= 100;
let r, g, b;
if (s === 0) {
r = g = b = l;
} else {
const hue2rgb = (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;
};
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
const p = 2 * l - q;
r = hue2rgb(p, q, h + 1/3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1/3);
}
return {
r: Math.round(r * 255),
g: Math.round(g * 255),
b: Math.round(b * 255)
};
}When to Use Each Format
HEX
Best for:
- Design specifications from Figma/Sketch
- Quick color definitions
- When you know the exact color
/* Common use */
.button {
background-color: #3498db;
border-color: #2980b9;
}RGB/RGBA
Best for:
- When you need transparency
- Programmatic color manipulation
- Working with color values as numbers
/* Overlay with transparency */
.overlay {
background-color: rgba(0, 0, 0, 0.5);
}HSL/HSLA
Best for:
- Creating color variations
- Theming systems
- Accessible color contrast
/* Easy color variations */
:root {
--primary-h: 220;
--primary-s: 90%;
--primary-l: 50%;
}
.primary {
background: hsl(var(--primary-h), var(--primary-s), var(--primary-l));
}
.primary-light {
/* Just change lightness */
background: hsl(var(--primary-h), var(--primary-s), 70%);
}
.primary-dark {
background: hsl(var(--primary-h), var(--primary-s), 30%);
}CSS Color Functions (Modern)
color-mix()
Mix two colors:
.mixed {
background: color-mix(in srgb, #ff0000 50%, #0000ff);
/* Results in purple */
}Relative Colors
Modify existing colors:
:root {
--brand: #3498db;
}
.lighter {
/* Make 20% lighter */
background: hsl(from var(--brand) h s calc(l + 20%));
}oklch() and oklab()
Perceptually uniform color spaces:
.modern {
/* L: lightness, C: chroma, H: hue */
background: oklch(70% 0.15 250);
}Color Manipulation Techniques
Darken/Lighten
function adjustLightness(hex, percent) {
const { r, g, b } = hexToRgb(hex);
const { h, s, l } = rgbToHsl(r, g, b);
const newL = Math.max(0, Math.min(100, l + percent));
const { r: nr, g: ng, b: nb } = hslToRgb(h, s, newL);
return rgbToHex(nr, ng, nb);
}
// Lighten by 20%
adjustLightness('#3498db', 20); // "#7ab8e8"
// Darken by 20%
adjustLightness('#3498db', -20); // "#1d6fa5"Saturate/Desaturate
function adjustSaturation(hex, percent) {
const { r, g, b } = hexToRgb(hex);
const { h, s, l } = rgbToHsl(r, g, b);
const newS = Math.max(0, Math.min(100, s + percent));
const { r: nr, g: ng, b: nb } = hslToRgb(h, newS, l);
return rgbToHex(nr, ng, nb);
}Complementary Color
function complementary(hex) {
const { r, g, b } = hexToRgb(hex);
const { h, s, l } = rgbToHsl(r, g, b);
// Add 180° to hue
const newH = (h + 180) % 360;
const { r: nr, g: ng, b: nb } = hslToRgb(newH, s, l);
return rgbToHex(nr, ng, nb);
}
complementary('#3498db'); // "#db7434"Analogous Colors
function analogous(hex) {
const { r, g, b } = hexToRgb(hex);
const { h, s, l } = rgbToHsl(r, g, b);
return [
hslToHex((h - 30 + 360) % 360, s, l),
hex,
hslToHex((h + 30) % 360, s, l)
];
}Accessibility and Contrast
WCAG Contrast Requirements
| Level | Normal Text | Large Text |
|---|---|---|
| AA | 4.5:1 | 3:1 |
| AAA | 7:1 | 4.5:1 |
Calculate Contrast Ratio
function luminance(r, g, b) {
const [rs, gs, bs] = [r, g, b].map(c => {
c /= 255;
return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
});
return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs;
}
function contrastRatio(hex1, hex2) {
const rgb1 = hexToRgb(hex1);
const rgb2 = hexToRgb(hex2);
const l1 = luminance(rgb1.r, rgb1.g, rgb1.b);
const l2 = luminance(rgb2.r, rgb2.g, rgb2.b);
const lighter = Math.max(l1, l2);
const darker = Math.min(l1, l2);
return (lighter + 0.05) / (darker + 0.05);
}
// Check accessibility
contrastRatio('#000000', '#ffffff'); // 21:1 (perfect)
contrastRatio('#3498db', '#ffffff'); // 2.79:1 (fails AA)Color Systems in CSS
CSS Custom Properties
:root {
/* Base colors */
--color-primary: #3498db;
--color-secondary: #2ecc71;
--color-accent: #e74c3c;
/* Semantic colors */
--color-success: var(--color-secondary);
--color-error: var(--color-accent);
--color-warning: #f39c12;
/* Shades */
--color-primary-light: #5faee3;
--color-primary-dark: #217dbb;
}
/* Usage */
.button {
background-color: var(--color-primary);
}
.button:hover {
background-color: var(--color-primary-dark);
}Tailwind-style Scale
:root {
--blue-50: #eff6ff;
--blue-100: #dbeafe;
--blue-200: #bfdbfe;
--blue-300: #93c5fd;
--blue-400: #60a5fa;
--blue-500: #3b82f6;
--blue-600: #2563eb;
--blue-700: #1d4ed8;
--blue-800: #1e40af;
--blue-900: #1e3a8a;
}Common Color Issues
Issue 1: Colors Look Different
Same HEX can look different due to:
- Monitor calibration
- Color profiles (sRGB vs P3)
- Browser rendering
Issue 2: Opacity Stacking
/* Overlapping transparent elements */
.overlay1 {
background: rgba(0, 0, 0, 0.5);
}
.overlay2 {
/* On top of overlay1, this isn't 75% opaque total */
background: rgba(0, 0, 0, 0.5);
}Issue 3: Color Space Clipping
Wide-gamut displays can show more colors than sRGB:
/* Use Display P3 when available */
.vibrant {
background: color(display-p3 1 0.2 0.1);
}Conclusion
Understanding color formats helps you write better CSS, create accessible designs, and build robust theming systems. Use HEX for quick definitions, RGBA for transparency, and HSL for programmatic color manipulation.
Use our free Color Converter tool to quickly convert between formats during development and design work.
Try Our Free Tools
Put these tips into practice with our free online tools. No signup required.
Explore Tools