Color Converter

Type a color in any notation, #3b82f6, rgb(59 130 246) or hsl(217 91% 60%), and the other two fields fill in. Use it when the design file gives you HEX and your CSS custom properties store HSL, so you can adjust lightness in one place.

Color Inputs
Preview

HEX, RGB and HSL describe the same colors

Pick the notation for what you need to edit. All three describe the same sRGB space. HEX is compact and copies cleanly out of a design file. RGB exposes the three channels. HSL separates hue from saturation and lightness, which is why theme systems often store colors that way: a hover state becomes one number changed instead of three recalculated.

For example, hsl(217 91% 60%) with lightness dropped to 50% gives a darker blue of the same hue, and you never touch the hue or saturation.

HSL is hard to convert by hand

HEX to RGB takes a calculator and a minute. HSL does not work that way: hue is an angle, saturation and lightness are percentages of a computed range, and the rounding is not obvious. A hand conversion is usually a shade or two off, which is enough to make a border look wrong next to the same color pasted from elsewhere.

Keep HEX or RGB as the source of truth. This tool rounds HSL to whole numbers, so a HEX to HSL to HEX round trip can land one unit off in a channel. HEX and RGB convert exactly. The converter also reads only opaque colors: 3- or 6-digit HEX, and the first three numbers of an rgb() or hsl() value, so alpha is dropped.

The preview swatch updates as you type, and each field has its own copy button. The math runs in the page, so nothing is uploaded.

How to use the Color Converter tool

  1. Type a color into any of the three fields: HEX such as #3b82f6 or 3b82f6, RGB such as rgb(59, 130, 246), or HSL such as hsl(217, 91%, 60%).
  2. The other two fields update as soon as the value is complete. A 3-digit HEX such as #abc expands to #aabbcc.
  3. The swatch on the right shows the current color so you can check it against your design.
  4. Click the copy icon next to a field to copy that value, or click Clear to empty all three fields.

How to convert HEX to RGB and HSL in JavaScript, PHP and Python

JavaScript / Node.js

function hexToRgb(hex) {
  let h = hex.replace("#", "");
  if (h.length === 3) h = [...h].map((c) => c + c).join(""); // #abc -> #aabbcc
  if (!/^[0-9a-f]{6}$/i.test(h)) throw new Error("Invalid HEX: " + hex);
  const n = parseInt(h, 16);
  return { r: n >> 16, g: (n >> 8) & 255, b: n & 255 };
}

function rgbToHex({ r, g, b }) {
  return "#" + [r, g, b].map((v) => v.toString(16).padStart(2, "0")).join("");
}

function rgbToHsl({ r, g, b }) {
  r /= 255; g /= 255; b /= 255;
  const max = Math.max(r, g, b), min = Math.min(r, g, b), 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 = max === r ? (g - b) / d + (g < b ? 6 : 0) : max === g ? (b - r) / d + 2 : (r - g) / d + 4;
  return { h: Math.round(h * 60), s: Math.round(s * 100), l: Math.round(l * 100) };
}

const rgb = hexToRgb("#3b82f6");
console.log(rgb);            // { r: 59, g: 130, b: 246 }
console.log(rgbToHex(rgb));  // #3b82f6
console.log(rgbToHsl(rgb));  // { h: 217, s: 91, l: 60 }

In the browser, the engine can do the conversion for you: set el.style.color = "#3b82f6" and read getComputedStyle(el).color to get rgb().

PHP

<?php
function hexToRgb(string $hex): array {
    $hex = ltrim($hex, "#");
    if (strlen($hex) === 3) {
        $hex = $hex[0] . $hex[0] . $hex[1] . $hex[1] . $hex[2] . $hex[2];
    }
    if (!preg_match('/^[0-9a-f]{6}$/i', $hex)) {
        throw new InvalidArgumentException("Invalid HEX: $hex");
    }
    return array_map("hexdec", str_split($hex, 2)); // [r, g, b]
}

function rgbToHex(int $r, int $g, int $b): string {
    return sprintf("#%02x%02x%02x", $r, $g, $b);
}

function rgbToHsl(int $r, int $g, int $b): array {
    $r /= 255; $g /= 255; $b /= 255;
    $max = max($r, $g, $b); $min = min($r, $g, $b);
    $l = ($max + $min) / 2;
    if ($max == $min) return [0, 0, round($l * 100)];
    $d = $max - $min;
    $s = $l > 0.5 ? $d / (2 - $max - $min) : $d / ($max + $min);
    $h = match ($max) {
        $r => ($g - $b) / $d + ($g < $b ? 6 : 0),
        $g => ($b - $r) / $d + 2,
        default => ($r - $g) / $d + 4,
    };
    return [round($h * 60), round($s * 100), round($l * 100)];
}

[$r, $g, $b] = hexToRgb("#3b82f6");
echo "rgb($r, $g, $b)", PHP_EOL;          // rgb(59, 130, 246)
echo rgbToHex($r, $g, $b), PHP_EOL;       // #3b82f6
[$h, $s, $l] = rgbToHsl($r, $g, $b);
echo "hsl($h, $s%, $l%)", PHP_EOL;        // hsl(217, 91%, 60%)

match() requires PHP 8.0; on older versions replace it with an if/elseif chain.

Python

import colorsys

def hex_to_rgb(value: str) -> tuple[int, int, int]:
    h = value.lstrip("#")
    if len(h) == 3:
        h = "".join(c * 2 for c in h)
    if len(h) != 6:
        raise ValueError(f"Invalid HEX: {value}")
    return tuple(int(h[i:i + 2], 16) for i in (0, 2, 4))

def rgb_to_hex(r: int, g: int, b: int) -> str:
    return f"#{r:02x}{g:02x}{b:02x}"

def rgb_to_hsl(r: int, g: int, b: int) -> tuple[int, int, int]:
    # colorsys works in 0..1 and returns H, L, S in that order
    h, l, s = colorsys.rgb_to_hls(r / 255, g / 255, b / 255)
    return round(h * 360), round(s * 100), round(l * 100)

rgb = hex_to_rgb("#3b82f6")
print(rgb)                  # (59, 130, 246)
print(rgb_to_hex(*rgb))     # #3b82f6
print(rgb_to_hsl(*rgb))     # (217, 91, 60)

colorsys returns HLS order (hue, lightness, saturation), so swap the last two values before writing hsl().

Common errors and how to fix them

Nothing updates when I type a HEX value
The value is not 3 or 6 hex digits yet. #3b82f is incomplete, and #3b82f6ff has an alpha channel the converter does not read. Enter exactly 3 or 6 digits from 0-9 and a-f.
RGB field accepts my input but the color looks wrong
The converter reads the first three numbers it finds, so rgb(255 0 0 / 50%) is read as 255, 0, 0 and the alpha is dropped. Check that each channel is between 0 and 255.
HSL converts back to a HEX that is one unit off
Hue, saturation and lightness are rounded to whole numbers, which loses precision. Keep the HEX or RGB value as the source of truth and use HSL for adjustments.
hsl(217, 91, 60) is rejected by the browser
Saturation and lightness need a percent sign: hsl(217, 91%, 60%). Hue is unitless or in deg.
Invalid property value for #RRGGBBAA in an old browser
Internet Explorer and very old Safari do not read 8-digit HEX with alpha. Use rgba() or hsla() with a 0 to 1 alpha instead.

Good to know

HEX and RGB are the same value written two ways. Both encode a 24-bit sRGB color, so converting between them loses nothing. HSL is a different coordinate system over the same colors: hue is an angle around the wheel, saturation is distance from gray, and lightness runs from black to white. It stores no extra information. Designers use it because "a bit lighter, a bit less saturated" is easier to reason about than three channel values.

Store theme colors as HSL parts to get variants by arithmetic. A hover state is the same hue and saturation with lightness dropped by 10. A muted version keeps hue and lightness and lowers saturation. For example, store the three numbers as separate custom properties, and hsl(var(--h) var(--s) var(--l) / 0.5) gives you a translucent version without converting anything.

Specifications and references

This tool follows the specifications below. Read them when you need the exact normative wording, for example to settle an edge case between two implementations.

Frequently Asked Questions

Which color formats are supported?

HEX (3- or 6-digit), RGB and HSL. Type a value in any one field and the other two update as soon as the value is complete.

When should I use HSL instead of HEX?

Use HSL when you need to adjust a color by hand. Lower lightness by 10 for a hover state, or lower saturation for a muted variant, and the hue stays put. Use HEX when you are copying values between a design file and CSS, since it is compact and every tool accepts it.

Does it support transparency?

No. The converter reads opaque colors only, and 8-digit HEX such as #3b82f6cc is not accepted. To add transparency, take the rgb() or hsl() output and add an alpha value, for example rgb(59 130 246 / 0.5).

Are the conversions exact?

HEX and RGB convert exactly. HSL is rounded to whole numbers, so converting HSL back to HEX can land one unit off in a channel. Keep HEX or RGB as your source of truth.

Can I preview the color?

Yes. The swatch next to the fields shows the current color and updates as you type, so you can check it before copying.

Related

Once you have the values, the CSS gradient generator blends between them. The CSS formatter tidies the stylesheet afterwards.

More CSS & Design Tools

Browse all css & design tools

Copied to clipboard!