HEX to HSL Color Converter
Last updated: 21 August 2026
Reviewed by Gavin · Research and drafting assisted by AI
HEX ⇄ HSL Color Converter
Convert a 6-digit (#RRGGBB) or 3-digit (#RGB) hex colour to Hue / Saturation / Lightness using the W3C CSS Color Module Level 4 algorithm — with a live swatch, WCAG contrast readout, lightness ramp, and harmony palette.
Accessibility contrast (WCAG 2.1)
Lightness ramp (same H and S)
Harmony palette (hue rotations)
Presets
Reference
HEX to HSL Color Converter
A hex colour code is the notation the web was built on: six hexadecimal digits, optionally compressed to three, describing how much red, green, and blue light a pixel should emit. It is compact and exact, but it is not human-readable in any useful sense. Nobody looks at #3B82F6 and thinks "that is a blue at ninety-one percent saturation, a little lighter than mid". HSL, Hue, Saturation, Lightness, is the model that makes that sentence possible. This converter takes any hex code, expands three-digit shorthand where needed, decodes each channel to a 0 to 255 integer, and applies the conversion algorithm defined in the W3C CSS Color Module Level 4 to produce the hue in degrees, the saturation as a percentage, and the lightness as a percentage. It then shows a live preview swatch, a copy-ready hsl() string, WCAG 2.1 contrast ratios against white and black, a nine-step lightness ramp, and a harmony palette built from hue rotations.
HSL belongs to the same family as HSB (also written HSV, Hue, Saturation, Brightness/Value). The hue axis is identical. The difference is the third coordinate: HSV defines Value as the maximum of the three normalised channels, so pure saturated hues sit at V = 100%; HSL defines Lightness as the midpoint between the maximum and minimum channels, so L = 100% is always white, L = 0% is always black, and the pure hues live at L = 50%. That single substitution is why HSL is the model built into CSS and why designers reach for it when building tint and shade scales.
How to Use
- Enter a hex code, type or paste into the hex field. The leading
#is optional. Both the six-digit form (#3B82F6) and the three-digit shorthand (#38F) are accepted; shorthand is expanded by doubling each digit, so#F80becomes#FF8800. - Read the result block, it shows the canonical hex, the CSS
hsl()string rounded to whole degrees and percentages, and the equivalentrgb()string. - Read the derived grid, full-precision hue, saturation, lightness, chroma (max − min), the three RGB channel integers, and the round-trip hex produced by converting the HSL values back to RGB. If the round-trip hex matches your input, the conversion is exact.
- Check accessibility, the contrast panel gives the WCAG 2.1 contrast ratio of your colour against white and against black, with a pass/fail note for AA normal text (4.5:1) and AA large text (3:1).
- Use the lightness ramp, nine swatches at the same hue and saturation, stepping lightness from 10% to 90%. This is a ready-made tint/shade scale for a design system.
- Use the harmony palette, complementary (+180°), triadic (+120° and +240°), and analogous (±30°) rotations at the same saturation and lightness.
- Click a preset, ten known-good colours, including Tailwind blue-500, Tailwind emerald, CSS gold, and steel blue.
The Formula
The conversion runs in two stages. First, hex to RGB. A six-digit hex code splits into three pairs; each pair is a base-16 integer in the range 0 to 255:
R = parseInt(RR, 16)
G = parseInt(GG, 16)
B = parseInt(BB, 16)
#RGB shorthand expands by digit-doubling: #F80 → #FF8800
Second, RGB to HSL. Normalise each channel to the 0 to 1 range, then find the largest and smallest of the three:
R' = R/255, G' = G/255, B' = B/255
max = max(R', G', B'), min = min(R', G', B'), d = max − min
L = (max + min) / 2
S = 0 when d = 0
S = d / (1 − |2L − 1|) otherwise
H = 0 when d = 0
H = 60° × (((G' − B') / d) mod 6) when max = R'
H = 60° × ((B' − R') / d + 2) when max = G'
H = 60° × ((R' − G') / d + 4) when max = B'
then wrap H into the range [0, 360)
The quantity d is the chroma, the colourfulness of the sample. When chroma is zero, the three channels are equal, the colour is a neutral grey, and hue is mathematically undefined; the specification and every practical implementation report hue as 0. The inverse conversion, HSL back to RGB, computes chroma C = (1 − |2L − 1|) × S, splits hue into sextants, and adds the offset m = L − C/2 to lift the result to the correct lightness. Both directions are specified in the W3C CSS Color Module Level 4, §7 "HSL Colors", with the widely copied pseudo-code appearing in CSS Color Level 3, §4.2.4.
Worked Examples
Example 1, #FF0000 (pure red). R = 255, G = 0, B = 0. Normalised: R′ = 1, G′ = 0, B′ = 0. max = 1, min = 0, d = 1. Lightness = (1 + 0)/2 = 0.5 → 50%. Saturation = 1 / (1 − |2(0.5) − 1|) = 1 / 1 = 1 → 100%. max is R′, so H = 60 × (((0 − 0)/1) mod 6) = 0°. Result: hsl(0, 100%, 50%).
Example 2, #3B82F6 (Tailwind blue-500). R = 59, G = 130, B = 246. Normalised: 0.231373, 0.509804, 0.964706. max = B′ = 0.964706, min = R′ = 0.231373, d = 0.733333. Lightness = (0.964706 + 0.231373)/2 = 0.598039 → 59.804%. Saturation = 0.733333 / (1 − |2(0.598039) − 1|) = 0.733333 / 0.803922 = 0.912195 → 91.220%. max is B′, so H = 60 × ((0.231373 − 0.509804)/0.733333 + 4) = 60 × 3.620321 = 217.219°. Result: hsl(217, 91%, 60%) when rounded for CSS.
Example 3, #808080 (mid grey). All three channels equal 128, so max = min = 0.501961 and d = 0. Chroma zero means saturation is zero and hue is undefined (reported as 0). Lightness = 0.501961 → 50.196%. Result: hsl(0, 0%, 50.196%). Note that this is not exactly 50%, the byte 128 is slightly above the true midpoint of 127.5.
Example 4, #F80 (shorthand). Digit-doubling expands this to #FF8800, giving R = 255, G = 136, B = 0. max = 1, min = 0, d = 1, so L = 50% and S = 100%. max is R′, so H = 60 × ((136/255 − 0)/1 mod 6) = 60 × 0.533333 = 32°. Result: hsl(32, 100%, 50%), identical to the six-digit form, as it must be.
Example 5, #800080 (CSS purple). R = 128, G = 0, B = 128. Normalised: 0.501961, 0, 0.501961. max = 0.501961, min = 0, d = 0.501961. Lightness = 0.250980 → 25.098%. Saturation = 0.501961 / (1 − |2(0.250980) − 1|) = 0.501961 / 0.501961 = 1 → 100%. Red and blue tie for the maximum; the algorithm's ordered comparison takes the blue branch, giving H = 60 × ((0.501961 − 0)/0.501961 + 4) = 60 × 5 = 300°. Result: hsl(300, 100%, 25.098%).
Example 6, #FFFFFF (white). All channels are 255, so max = min = 1, d = 0, S = 0, and L = 100%. Result: hsl(0, 0%, 100%). Every value of hue produces white at L = 100%, which is precisely the property that makes HSL convenient for tint scales.
Where It Shows Up
- CSS authoring.
hsl()andhsla()are native CSS colour functions. Writinghsl(217 91% 60%)and thenhsl(217 91% 45%)for a hover state is far more readable than swapping two unrelated hex codes. - Design systems and tokens. Tailwind, Material, Radix, and most in-house token systems generate 50→950 colour scales by holding hue roughly constant and stepping lightness, exactly what the lightness ramp in this tool produces.
- Accessibility work. Lightness correlates loosely with perceived brightness, so nudging L is the fastest way to fix a failing contrast ratio without changing brand hue.
- Palette generation. Complementary, triadic, split-complementary, and analogous schemes are all defined as hue rotations, which are trivial in HSL and awkward in hex.
- Data visualisation. Sequential and diverging colour scales in D3, Vega, and Chart.js are usually parameterised in a cylindrical space; HSL is the simplest such space available natively in the browser.
- Theming and dark mode. A single hue plus an inverted lightness curve gives a coherent dark theme from an existing light palette.
- SVG and canvas work. Both accept
hsl()strings directly, so programmatic colour manipulation avoids hex string surgery entirely.
Common Mistakes
Confusing HSL with HSB/HSV. They share a hue axis but not a third coordinate. hsl(0, 100%, 50%) and hsv(0, 100%, 100%) are both pure red; hsl(0, 100%, 100%) is white while hsv(0, 100%, 100%) is still red. Photoshop's picker is HSB, CSS is HSL, reading a value from one into the other silently produces the wrong colour.
Treating lightness as perceived brightness. Pure blue hsl(240, 100%, 50%) and pure yellow hsl(60, 100%, 50%) have the same L but wildly different apparent brightness, because the human eye is far more sensitive to green than to blue. For contrast decisions, use the WCAG relative luminance figure shown in the tool, not L.
Rounding too early. hsl(217, 91%, 60%) does not convert back to #3B82F6; it lands on #3C82F5. Keep full precision through intermediate steps and round only at the point of output, or store the hex as the source of truth.
Forgetting shorthand expansion. #F80 is not #0F0800 or #F80000. Each digit doubles: #FF8800. Skipping expansion is the single most common bug in hand-rolled parsers.
Assuming hue is meaningful for greys. Any neutral has zero chroma and therefore undefined hue. Sorting a palette by hue will scatter greys arbitrarily unless you handle the achromatic case explicitly.
Frequently Asked Questions
What is the difference between HSL and HSB/HSV? Both models share the same hue axis measured in degrees around a colour wheel, and both call their second coordinate saturation, but the third coordinate differs. HSV (also called HSB) defines Value or Brightness as the maximum of the normalised red, green, and blue channels, so a fully saturated pure hue sits at V = 100% and white is only reachable by dropping saturation to zero. HSL defines Lightness as the average of the maximum and minimum channels, so L = 0% is always black, L = 100% is always white regardless of hue, and the pure saturated hues sit exactly halfway at L = 50%. In practice, HSV maps better to the way physical colour pickers are drawn, while HSL maps better to the way tint-and-shade scales are built, which is why CSS standardised on HSL.
Why should I use HSL instead of hex in my CSS? Because HSL encodes design intent and hex does not. If your brand blue is hsl(217, 91%, 60%), then the hover state, the disabled state, the focus ring, and the dark-mode variant are all small adjustments to a single number, and anyone reading the stylesheet can see the relationship at a glance. With hex codes, #3B82F6, #2563EB, and #1D4ED8 look like three unrelated strings even though they are the same hue at three lightness levels. Modern CSS also supports the space-separated syntax hsl(217 91% 60% / 0.5) with an alpha channel, and color-mix() and relative colour syntax operate naturally on HSL components.
Does converting hex to HSL and back always give the same colour? It does if you keep full floating-point precision through the round trip. Hex holds 8 bits per channel, 16,777,216 possible colours, while HSL as computed here uses doubles, so the HSL representation carries strictly more information than the hex it came from and the inverse conversion recovers the original bytes exactly. The tool shows this round-trip hex so you can verify it. Precision is lost only when you round the HSL values before converting back, which is why hsl(217, 91%, 60%) returns #3C82F5 rather than #3B82F6. Store hex as the canonical value and treat rounded HSL as a display convenience.
How does HSL help with accessibility and contrast ratios? Contrast under WCAG 2.1 is computed from relative luminance, a weighted sum of gamma-corrected channel values (0.2126 R + 0.7152 G + 0.0722 B), not from lightness. However, within a single hue, increasing L reliably increases luminance and decreasing L reliably decreases it, so HSL gives you a one-dimensional dial for fixing a failing ratio while keeping the brand hue intact. The practical workflow is: check the ratio, step lightness by 5 to 10%, re-check. This tool reports the exact ratio against both white and black backgrounds along with the AA thresholds, 4.5:1 for normal text, 3:1 for large text (18pt, or 14pt bold) and for user-interface components under WCAG 2.1 §1.4.11.
How do I generate a colour palette from a single hex code? Convert to HSL first, then manipulate one coordinate at a time. For a tint and shade scale, hold hue and saturation fixed and step lightness, the nine-step ramp in this tool from L = 10% to L = 90% is exactly that. For harmony schemes, hold saturation and lightness fixed and rotate hue: +180° gives the complement, +120° and +240° give a triad, ±30° gives analogous neighbours, and +150°/+210° gives a split complement. Real design systems usually also taper saturation slightly at the extremes of the lightness ramp, because very light and very dark colours look artificial at full saturation. Starting from HSL makes each of these operations a single arithmetic step.
Why does my grey colour show a hue of 0 degrees? Because hue is genuinely undefined for achromatic colours. When the red, green, and blue channels are equal, the chroma term d = max − min is zero, and every hue formula divides by d. Rather than produce a division by zero, the specification and every conforming implementation report hue as 0 and saturation as 0. The lightness value still carries all the information: hsl(0, 0%, 50.196%) fully describes #808080. A useful consequence is that any hue paired with 0% saturation renders the same grey, so you can safely carry a nominal brand hue through your neutral tokens without affecting output.
Is the three-digit hex shorthand exactly equivalent to six digits? Yes, but only for the 4,096 colours it can express. The shorthand #RGB expands to #RRGGBB by doubling each digit, so #F80 is #FF8800 and #ABC is #AABBCC. Digit-doubling is chosen because it maps the 4-bit range 0 to 15 onto the 8-bit range 0 to 255 with the endpoints preserved: 0 → 00 = 0 and F → FF = 255. Colours like #3B82F6 have no shorthand form because the digit pairs are not repeats. Note that CSS Color 4 also defines four- and eight-digit forms that append an alpha channel (#RGBA and #RRGGBBAA); this converter handles the opaque three- and six-digit forms.
Q: Can the HEX to HSL Converter, Hue, Saturation & Lightness be used for professional or commercial purposes? A: Yes, the HEX to HSL Converter, Hue, Saturation & Lightness provides mathematically correct results that are suitable for professional, commercial, and educational use. For the HEX to HSL Converter, Hue, Saturation & Lightness, For the HEX to HSL Converter, Hue, Saturation & Lightness, For high-stakes applications (medical, legal, financial), verify results with a domain expert. For the HEX to HSL Converter, Hue, Saturation & Lightness, the HEX to HSL Converter, Hue, Saturation & Lightness formulas used are well-established and validated against reference standards.
Q: How often are the HEX to HSL Converter, Hue, Saturation & Lightness formulas updated? A: the HEX to HSL Converter, Hue, Saturation & Lightness formulas are based on established scientific, mathematical, or industry-standard references and rarely require updates. when standards change, the HEX to HSL Converter, Hue, Saturation & Lightness is updated to reflect the current authoritative source.
References
W3C, CSS Color Module Level 4, §7 "HSL Colors" and §12 "Converting Colors", the normative definition of the hsl() notation and the RGB↔HSL convert: https://www.w3.org/TR/css-color-4/#the-hsl-notation. W3C, CSS Color Module Level 3, §4.2.4, which carries the widely reproduced conversion pseudo-code. W3C, Web Content Accessibility Guidelines (WCAG) 2.1, Success Criteria 1.4.3 (Contrast Minimum), 1.4.6 (Contrast Enhanced), and 1.4.11 (Non-text Contrast), plus the relative luminance definition used for the contrast readout. IEC 61966-2-1 defines the sRGB colour space that hex codes implicitly address. MDN Web Docs, "<color>, CSS" and "hsl()", for practical browser-support notes.