HSL to RGB 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

However an HSL color was chosen or generated, it has to become RGB before it can actually be drawn — every display is built from red, green, and blue light-emitting sub-pixels, and modern browsers’ native hsl() CSS support is really just the browser doing this exact conversion for you invisibly. The moment you’re working below that convenience layer — a Canvas 2D context’s numeric APIs, a WebGL shader’s color uniform, an ImageData buffer you’re writing pixels into directly — HSL stops being accepted automatically, and converting it to RGB yourself becomes a required step, not an optional one.

The formula (the reverse of RGB-to-HSL) reconstructs three RGB channels from hue, saturation, and lightness using a piecewise function over six 60°-wide segments of the color wheel — which segment the hue falls in determines which of the three RGB channels is rising, which is falling, and which is holding steady. hsl(340, 82%, 52%) — a hue just past magenta, heading back toward red — works out to rgb(233, 32, 99): a vivid pink-red, with red as the dominant channel, blue as a strong secondary component (magenta’s influence), and green suppressed almost to nothing. Unlike the RGB-to-HSL direction, where hue/saturation/lightness get rounded to whole numbers for display, RGB channels are always whole numbers by definition — 0 to 255, nothing in between — so this direction’s rounding happens at the very end of the calculation rather than being a display-only concern.

One place this conversion shows up as a genuinely useful technique, not just a necessary chore: generating a set of visually distinct colors programmatically — a chart’s category palette, a set of user-avatar background colors, tag/label colors — is far easier in HSL than in RGB. Holding saturation and lightness constant and stepping the hue evenly around the 360° wheel (dividing 360 by the color count) produces colors that are maximally, evenly spread apart with almost no effort; there’s no equivalently simple formula for “N evenly distinct colors” starting from RGB directly. Each generated HSL value still needs converting to RGB (or hex) before a canvas or chart library can actually paint it.

Converting HSL to RGB programmatically

JavaScript, plus a practical batch example — generating an evenly-spaced palette for a chart:

function hueToChannel(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;
}

function hslToRgb(h, s, l) {
  const hn = h / 360, sn = s / 100, ln = l / 100;
  if (sn === 0) {
    const v = Math.round(ln * 255);
    return { r: v, g: v, b: v };
  }
  const q = ln < 0.5 ? ln * (1 + sn) : ln + sn - ln * sn;
  const p = 2 * ln - q;
  return {
    r: Math.round(hueToChannel(p, q, hn + 1 / 3) * 255),
    g: Math.round(hueToChannel(p, q, hn) * 255),
    b: Math.round(hueToChannel(p, q, hn - 1 / 3) * 255),
  };
}

console.log(hslToRgb(340, 82, 52));
// { r: 233, g: 32, b: 99 }

// A 5-color chart palette, hues evenly spaced around the wheel:
const palette = Array.from({ length: 5 }, (_, i) => hslToRgb((i * 360) / 5, 70, 55));

Python, via colorsys.hls_to_rgb (hue, lightness, saturation order):

import colorsys

r, g, b = colorsys.hls_to_rgb(340 / 360, 0.52, 0.82)
print(round(r * 255), round(g * 255), round(b * 255))
# 233 32 99

Frequently asked questions

Why can't a browser or a canvas just render an HSL color directly?
Modern CSS actually does accept hsl() as a value, but that's the browser converting it to RGB internally before it ever reaches a pixel — every physical display renders through red, green, and blue sub-pixels, full stop, so an HSL value has to become RGB channel intensities at some point no matter what wrote it. Canvas's 2D context, WebGL shader uniforms, and most lower-level graphics APIs skip that convenience layer entirely and expect RGB (or raw channel numbers) directly, which is when converting HSL to RGB yourself becomes necessary rather than automatic.
How do I generate a set of evenly-spaced colors using HSL?
Keep saturation and lightness fixed and step the hue evenly around the 360° wheel — dividing 360 by however many colors you need and multiplying by each index gives hues that are maximally, evenly spread apart (e.g. 5 colors at 0°, 72°, 144°, 216°, 288°). This is a common way to generate a chart's category-color palette or a set of visually distinct tags/labels programmatically, and it only works cleanly in HSL — the RGB equivalent of "evenly spaced colors" has no simple formula.
Does the RGB result always land on whole numbers?
Yes, by construction — RGB channels are always integers 0-255, so the HSL-to-RGB formula rounds its output to the nearest whole number regardless of how precise the input hue/saturation/lightness was. This is the reverse of the RGB-to-HSL direction, where the *output* (hue/saturation/lightness) gets rounded instead.
What happens to alpha in this conversion?
HSL and RGB have entirely separate optional alpha channels — HSLA's alpha and RGBA's alpha are the same 0-1 value, just carried alongside whichever three color numbers you're using. Converting the hue/saturation/lightness math itself doesn't touch alpha at all; it passes through unchanged.
Is my color sent to a server?
No. The conversion runs entirely in your browser using plain arithmetic — nothing is uploaded, logged, or stored.

Related Color Converter pages

Looking for a different pair or algorithm? Here are the other specific versions, plus the general tool for everything else: