RGB to HSL Converter
Optional shortcut — sets the fields below. No transparency support (a browser limitation of this control), so use the HEX/RGB/HSL fields directly for a translucent color.
#RGB, #RGBA, #RRGGBB, or #RRGGBBAA — the # is optional
rgb(R, G, B) or rgba(R, G, B, A) — R/G/B 0-255, A 0-1
hsl(H, S%, L%) or hsla(H, S%, L%, A) — H 0-360, A 0-1
RGB and HSL describe the same color space through two different mathematical lenses, and converting between them is where that relationship becomes concrete rather than conceptual. RGB describes a color as three independent light intensities — how much red, how much green, how much blue — while HSL describes the same point in color space as a position on a wheel (hue) plus how far from gray it is (saturation) and how close to black or white (lightness). Neither is more “correct”; they’re two coordinate systems for the same underlying space, the way Cartesian and polar coordinates both describe the same point on a plane.
The formula, worked through concretely: lightness is simply the average of the largest and smallest channel — for rgb(180, 140, 60), that’s (180 + 60) / 2 = 120 out of 255, roughly 47%. Saturation measures the gap between the largest and smallest channel relative to that lightness — a wide gap (like here, 180 vs. 60) means a more saturated color; three equal channels would collapse to 0% regardless of how bright or dark they are, since equal RGB values are always some shade of gray. Hue depends on which channel wins: red is largest here, which places the hue somewhere in the 0°-60° slice of the wheel (red toward yellow), and the exact position — 40° — comes from how much green (the second-largest channel) has caught up to red relative to how far blue has fallen behind. The result, hsl(40, 50%, 47%), is a moderately saturated amber-brown — which is exactly what rgb(180, 140, 60) looks like.
This conversion shows up constantly in image and computer-vision code: a decoded photo or video frame is RGB data (one byte per channel, straight from the sensor or file format), but tasks like sorting pixels by dominant color, thresholding a mask by hue range, or building a color histogram are all far easier to reason about in HSL than in raw RGB — “select the orange-ish pixels” is a hue range, not three separate channel comparisons.
Converting RGB to HSL programmatically
JavaScript, the formula above as code:
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;
const l = (max + min) / 2;
if (max === min) {
h = s = 0;
} else {
const d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
if (max === r) h = (g - b) / d + (g < b ? 6 : 0);
else if (max === g) h = (b - r) / d + 2;
else h = (r - g) / d + 4;
h *= 60;
}
return { h: Math.round(h), s: Math.round(s * 100), l: Math.round(l * 100) };
}
console.log(rgbToHsl(180, 140, 60));
// { h: 40, s: 50, l: 47 }
Python, via the standard library’s colorsys.rgb_to_hls (note: hue, lightness, saturation order, and 0-1 fractions rather than 0-255/percent):
import colorsys
h, l, s = colorsys.rgb_to_hls(180 / 255, 140 / 255, 60 / 255)
print(round(h * 360), round(s * 100), round(l * 100))
# 40 50 47Frequently asked questions
What's actually happening mathematically when RGB converts to HSL?
Why did this particular pixel — rgb(180, 140, 60) — land at hue 40?
Does Python have RGB-to-HSL conversion built in?
colorsys module — though it's named rgb_to_hls (hue, lightness, saturation, in that argument order) rather than hsl, and it expects/returns every value as a 0-1 fraction rather than the 0-255 channels and 0-100% you'd write in CSS, so both ends need a small unit conversion.Is 50% saturation for this color considered high or low?
Is my color sent to a server?
Related Color Converter pages
Looking for a different pair or algorithm? Here are the other specific versions, plus the general tool for everything else: