HEX 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

A hex code and its HSL equivalent describe the same color, but only one of them is easy for a person to reason about. #7c3aed tells you nothing at a glance about whether the color is vivid or muted, light or dark, or what happens if you nudge it slightly — the three hex pairs are red, green, and blue channel bytes, and changing “just the lightness” means recalculating all three together, by trial and error. HSL separates the same color into three independent, meaningful knobs: hue (which color, as a position on a 360° wheel), saturation (how intense or muted), and lightness (how light or dark) — turning “make this a bit lighter” from a guessing game into changing one number.

Getting from hex to HSL is genuinely a two-step process, not one: hex encodes RGB channel bytes, not hue/saturation/lightness directly, so the first step splits the hex string into red, green, and blue (the same parsing a hex-to-RGB conversion does), and only the second step runs the actual HSL math over those three channel values — comparing which channel is largest and smallest to derive hue, and how far apart they are to derive saturation. There’s no shortcut that skips the RGB step, because HSL’s definition is built entirely on the relationships between the RGB channels, not on the hex digits themselves.

Taking this specific color as an example: #7c3aed converts to hsl(262, 83%, 58%). The hue, 262°, sits just past blue (240°) heading toward magenta — the blue-violet/purple range, matching what the color actually looks like. An 83% saturation is close to fully vivid (100% would be as intense as that hue can get; 0% would be gray), which is why the color reads as a bold, saturated purple rather than a muted lavender. A 58% lightness sits just above the midpoint, giving a color that’s neither washed-out pale nor near-black — reading each of the three numbers this way is exactly the point of converting to HSL in the first place.

Converting hex to HSL programmatically

JavaScript, as the two explicit steps described above:

function hexToRgb(hex) {
  const h = hex.replace("#", "");
  return {
    r: parseInt(h.slice(0, 2), 16),
    g: parseInt(h.slice(2, 4), 16),
    b: parseInt(h.slice(4, 6), 16),
  };
}

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, 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) };
}

const { r, g, b } = hexToRgb("#7c3aed");
console.log(rgbToHsl(r, g, b));
// { h: 262, s: 83, l: 58 }

Python, using the standard library’s colorsys for the RGB→HSL step (note: colorsys calls it rgb_to_hls — hue, lightness, saturation, in that order — not hsl):

import colorsys

def hex_to_rgb(hex_color):
    h = hex_color.lstrip("#")
    return int(h[0:2], 16), int(h[2:4], 16), int(h[4:6], 16)

r, g, b = hex_to_rgb("#7c3aed")
h, l, s = colorsys.rgb_to_hls(r / 255, g / 255, b / 255)
print(round(h * 360), round(s * 100), round(l * 100))
# 262 83 58

Frequently asked questions

Why convert hex to HSL instead of just adjusting the hex digits directly?
Because hex's three pairs don't correspond to anything you can reason about directly — there's no single digit that means "lighter" or "more vivid." Making #7c3aed lighter by hand means recalculating all three channel pairs together and guessing; in HSL, it's one number: raise the lightness percentage and every other property of the color (its hue, how saturated it is) stays exactly the same.
Why can't hex convert to HSL in a single step?
Because hex doesn't encode hue, saturation, or lightness directly — it encodes red, green, and blue channel bytes, the same information RGB has. Converting hex to HSL is really two conversions in sequence: hex to RGB (splitting the string into channel bytes), then RGB to HSL (the actual hue/saturation/lightness math). There's no shortcut that skips the RGB step, since HSL is defined in terms of the RGB channels' relationships to each other, not the hex digits themselves.
What does this color's hue of 262° actually mean?
It's a position on the color wheel, where 0°/360° is red, 120° is green, and 240° is blue. 262° sits just past blue, in the blue-violet/purple range — which matches #7c3aed visually. Moving the hue up or down from there without touching saturation or lightness shifts the color around the wheel while keeping it equally vivid and equally bright.
Is 83% saturation considered vivid or muted?
Vivid. Saturation measures how far a color is from gray at the same lightness — 0% would be a pure gray, 100% is as intense/colorful as that hue and lightness can get. 83% is close to fully saturated, which is why this purple reads as bold rather than dusty or pastel.
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: