Convert RGB to HSL

Convert RGB color values to HSL instantly. Get the hsl() equivalent for building color scales, adjusting tones, or writing maintainable dynamic CSS.

ZERO UPLOAD · ALL LOCAL
  1. Drag the crosshair on the gradient canvas to pick a color, or type directly into any format field to convert it instantly.
  2. Use the hue slider to change the color family and the opacity slider (or Opacity % field) to adjust transparency.
  3. The CSS Named field shows the closest CSS color name to your pick. The small swatch beside it shows what that named color actually looks like.
  4. The Contrast Check section shows the WCAG AA / AAA rating for black text and white text on your color.
  5. Click Copy next to any field to copy that format value to your clipboard.

Worked examples for this use case

Button color → hover state derivation

Before
rgb(59, 130, 246)
After
hsl(217, 91%, 60%)

Set lightness to 50% for a darker hover: hsl(217, 91%, 50%).

Canvas pixel → design token

Before
rgb(200, 100, 50)
After
hsl(20, 60%, 49%)

Round lightness to 50% for a clean palette token baseline.

Hue
Opacity
Invalid format

Contrast Check

Text
Black on color
Text
White on color

RGB to HSL Color Converter

RGB integers do not expose intuitive editing handles.

When a developer needs to darken a button by 10%, adjusting all three RGB channels independently risks shifting the perceived hue unintentionally. Converting to HSL first isolates the lightness value so it can be changed alone: the hue angle and saturation stay fixed, and the color family stays visually consistent through adjustments. This separation between identity (hue) and intensity (lightness) is the core reason HSL exists as a design-facing format.

How the conversion works

Converting RGB to HSL begins by normalizing each 0–255 integer to a 0–1 float. The algorithm identifies the maximum and minimum channel values. Lightness is their average. Saturation measures the channel spread relative to the lightness distance from the extremes: above lightness 0.5, it uses (max − min) / (2 − max − min); below 0.5, it uses (max − min) / (max + min). Hue maps the maximum channel to its 0–360 sextant position, with the secondary channels determining the fractional offset within that sextant.1

Why saturation depends on lightness

The saturation formula branches at lightness 0.5 because the same channel spread looks different depending on how bright the color is. When you compare a 10-unit channel spread on a dark color versus the same spread on a light color, the dark one appears more saturated to the eye because the smaller absolute values create a larger relative difference. By normalizing relative to the lightness extremes, the dual formula ensures consistent saturation percentages regardless of where the color sits on the lightness scale.

The branching formula also protects you from surprising results when you build scales. A mid-tone and a highlight of the same hue can both register low saturation, but only the branch above lightness 0.5 keeps the percentage meaningful as colors approach white. Keeping the math tied to the lightness extremes means a tint and its base shade report saturation values that actually compare, instead of drifting apart as the color gets brighter.

Where this comes up

Browser DevTools and JavaScript color pickers emit rgb() values. Canvas getImageData() returns raw r, g, b integers per pixel. Consequently, any pipeline that begins by reading color from a rendered surface and needs to derive a lighter or darker variant must pass through HSL. Building on this, CSS color-mix() and color() functions can express similar transformations natively in modern browsers, but server-side and legacy environments that do not support CSS Color Level 4 still require the explicit RGB-to-HSL step in JavaScript.

Reading pixel colors from a canvas

When you sample a pixel from an HTML canvas using getImageData(), the returned data is always an RGBA quadruplet of 0–255 integers. If your application needs to determine whether a pixel is warm or cool, or whether it falls within a specific hue range for a color-based selection tool, converting those RGB integers to HSL gives you the hue angle directly. This is particularly useful for image analysis features like background removal or color-based masking, where the hue channel provides a more reliable signal than raw RGB values.

Edge cases and rounding

Achromatic inputs (r, g, and b all equal) produce saturation 0. The hue angle is mathematically undefined for grey; most implementations return 0° by convention.1 Floating-point division in the saturation formula produces values rounded to two decimal places. Yet a round-trip of RGB → HSL → RGB may return an integer 1 different in one channel because of this rounding.2 Alpha channels in rgba() are not part of the HSL model and must be tracked separately through any workflow that modifies HSL values.

Handling grey in design token pipelines

When your design system generates color scales programmatically, grey edge cases appear more often than you might expect. A color like rgb(128, 128, 128) converts to hsl(0, 0%, 50%), where the hue of 0° is arbitrary. If you later rotate the hue to create a warm variant, the original grey will shift to red instead of remaining neutral. The safe approach is to check whether saturation rounds to zero before applying hue-based transformations, and treat those colors as fixed neutrals that should not participate in hue rotation logic.

Generating color scales from a single RGB value

Converting an RGB color to HSL gives you the coordinates you need to generate a full shade scale. Take the hue and saturation from the HSL output, then create variants by stepping lightness from 95% down to 10% in equal increments. Each step is a visually related shade of the original color, suitable for building button hover states, card backgrounds, and text color hierarchies.

A practical 10-step scale uses lightness values of 97%, 93%, 88%, 80%, 70%, 58%, 46%, 35%, 24%, and 14%. These values are not evenly spaced because HSL lightness is not perceptually uniform: the steps are compressed at the light and dark ends to avoid colors that look too similar. Building on this, after generating the HSL scale, convert each step to HEX for use in CSS custom properties. The resulting palette is hue-consistent (all shades share the same hue angle) and saturation-consistent (all shades share the same saturation percentage), which gives the palette a cohesive visual identity.

RGB to HSL for CSS color-mix() and relative color syntax

CSS Color Level 4 introduces color-mix() and relative color syntax, both of which work in a specified color space.3 color-mix(in hsl, rgb(59, 130, 246), white) mixes your RGB color with white in HSL space, producing a lighter tint. The relative color syntax goes further: from rgb(59, 130, 246) calc(l + 0.1) c h takes the HSL equivalent and increases lightness by 10 percentage points.

These CSS features require the browser to internally convert RGB to HSL (or whatever space you specify). By converting explicitly first, you can preview the HSL coordinates and predict what the CSS functions will produce. Building on this, the in hsl keyword in color-mix() is important: mixing in HSL produces different results than mixing in sRGB or OKLCH because the interpolation happens in different color spaces. HSL mixing tends to produce more perceptually intuitive results for tints and shades, while OKLCH mixing produces the most perceptually uniform gradients.

Handling alpha channels when converting RGB to HSL

The HSL color model has no alpha channel. When you convert rgba(59, 130, 246, 0.5) to HSL, the alpha value is discarded and you get hsl(217, 91%, 60%) with no transparency information. To preserve alpha, you must track it separately and reapply it after the HSL conversion. In CSS, this means using hsla() instead of hsl(): hsla(217, 91%, 60%, 0.5).

CSS Color Level 4 introduces slash-separated alpha syntax for hsl(): hsl(217 91% 60% / 0.5).3 This is the recommended modern form because it is consistent with other CSS color functions and works with color-mix(). Building on this, if your workflow involves converting rgba() to HSL and back, always store the alpha value alongside the HSL coordinates as a separate variable. Losing the alpha during conversion is a common source of bugs in design token pipelines that treat color as a single value rather than as a combination of color coordinates and opacity.

When to use this

Use this when you need lighter, darker, or more saturated variants of an existing RGB color: hold the hue and saturation fixed while stepping lightness to darken a button without shifting its hue.

Examples

Button color → hover state derivation

Before
rgb(59, 130, 246)
After
hsl(217, 91%, 60%)

Set lightness to 50% for a darker hover: hsl(217, 91%, 50%).

Canvas pixel → design token

Before
rgb(200, 100, 50)
After
hsl(20, 60%, 49%)

Round lightness to 50% for a clean palette token baseline.

Sources
  1. 1.

    "HSL and HSV," Wikipedia, en.wikipedia.org, accessed June 2026. https://en.wikipedia.org/wiki/HSL_and_HSV

  2. 2.

    "hsl() CSS function," MDN Web Docs, developer.mozilla.org, accessed June 2026. https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/color_value/hsl

  3. 3.

    Martin R, "Is there a way to prevent from precision lossing from converting from RGB, to HSV then back to RGB?," Stack Overflow, stackoverflow.com, February 2022. https://stackoverflow.com/questions/71071103/

FAQ