Skip to content

Hex to HSL Converter

Convert any hex color to HSL in your browser — 3-digit, 6-digit, 8-digit alpha all supported. Free, instant, no signup, your colors never leave the page.

No Tracking Runs in Browser Free
All color conversion happens locally in your browser. No data is sent to any server.
Gamut: sRGB Display P3 Rec2020
Contrast vs:
AA AA-Lg AAA AAA-Lg · APCA Lc
Color blindness simulation (8 types)
Protanopia (red-blind)
Deuteranopia (green-blind)
Tritanopia (blue-blind)
Achromatopsia (total)
Protanomaly (red-weak)
Deuteranomaly (green-weak)
Tritanomaly (blue-weak)
Achromatomaly (partial)
Tints / Shades / Tones / Harmonies

Tints

Shades

Tones

Harmonies

Copy as code
Common colors reference
Reviewed for CSS Color 4 §6.4 conformance, 3/4/6/8-digit hex shape support, alpha-pair decoding correctness, and round-trip stability between HEX and HSL across the 0-360° hue and 0-100% S/L ranges. — Go Tools Engineering Team · May 27, 2026

What Is a Hex to HSL Converter?

A hex to HSL converter is a small utility that turns a hex color code (`#3b82f6`) into the cylindrical Hue / Saturation / Lightness triple that encodes the same sRGB color (`hsl(217 91% 60%)`). Hex codes are the terse base-16 string designers and developers paste between Figma, Sketch, Photoshop, brand-guideline PDFs, and CSS stylesheets — three 8-bit channels packed into a 6-character `#RRGGBB` form, anchored to the sRGB color space defined by IEC 61966-2-1 in 1996. HSL is a cylindrical reshape of that same color space onto three more-designer-friendly axes: a hue angle on the color wheel, a chromatic saturation percent, and a lightness percent. Developers convert HEX → HSL constantly: to define a brand color as a CSS variable and then compose lighter or darker shades by adjusting only L, to feed a color-picker UI that displays Hue and SL as separate controls, to generate tint and shade ramps for a design system, or to perform runtime CSS variable math via `hsl(from var(--primary) h s calc(l + 10%))` for derived theme tokens. This tool runs the conversion live as you type, with no "Convert" button to click, and surfaces every other common color format (RGB, OKLCH, OKLAB, HSV, HWB, CMYK, plus the 148 CSS named colors) alongside the HSL output for free.

**The HSL format itself deserves a closer look.** HSL = Hue (0-360°), Saturation (0-100%), Lightness (0-100%). Hue is angular position on the color wheel — 0° is red, 60° is yellow, 120° is green, 180° is cyan, 240° is blue, 300° is magenta, and 360° wraps back to red. Saturation is chromatic intensity from 0% (achromatic gray) to 100% (fully chromatic with no gray content). Lightness is brightness from 0% (pure black, regardless of hue or saturation) through 50% (the pure hue at full chroma) to 100% (pure white, regardless of hue or saturation). Alvy Ray Smith published the original derivation in 1978 as part of the early computer-graphics push to give designers coordinate systems closer to their cognitive model of color than raw RGB channel addressing. The model has been in CSS since CSS3 (2010) and ships in every browser back to IE 9. The original CSS syntax used commas: `hsl(217, 91%, 60%)` for opaque, `hsla(217, 91%, 60%, 0.5)` for alpha-bearing. CSS Color 4 (W3C Candidate Recommendation since 2022) added a modern space-separated form: `hsl(217 91% 60%)` and `hsl(217 91% 60% / 0.5)` with slash-prefixed alpha — same syntax shape as the other CSS Color 4 functional notations (`rgb()`, `lab()`, `oklch()`, `color()`). Hue can also be expressed in turns (`hsl(0.6turn 91% 60%)`) or radians (`hsl(3.787rad 91% 60%)`), all equivalent to the canonical degree form. Every evergreen browser parses every syntactic flavor; the tool emits the modern space-separated form by default.

The conversion math goes both directions cleanly. **HEX → HSL** is a two-step pipeline. First, parse the 6-digit hex `#RRGGBB` as three 2-digit base-16 numbers via `parseInt(hex.slice(1, 3), 16)` etc. to get integer RGB channels in 0-255. Second, normalize each channel to 0-1 by dividing by 255, then compute `max = Math.max(r, g, b)`, `min = Math.min(r, g, b)`, `delta = max - min`. Lightness is the average of max and min: `L = (max + min) / 2`. Saturation is conditional on lightness: when L ≤ 0.5, `S = delta / (max + min)`; when L > 0.5, `S = delta / (2 - max - min)`. Equivalently in the CSS Color 4 §6.4 form, `S = delta / (1 - |2L - 1|)` (with S = 0 when delta = 0). Hue is piecewise on which channel is max: when R is max, `H = ((G - B) / delta) % 6`; when G is max, `H = (B - R) / delta + 2`; when B is max, `H = (R - G) / delta + 4`; multiply by 60 to scale to degrees, add 360 if negative. The inverse (HSL → HEX, via RGB) uses the helper `f(n) = L - a * max(-1, min(k-3, 9-k, 1))` where `a = S * min(L, 1-L)` and `k = (n + H/30) mod 12`, applied with n = 0, 8, 4 to produce R, G, B respectively, then scaled to 0-255 and hex-encoded.

**Why HSL is still useful.** Intuitive sliders — adjusting L predictably brightens or darkens without breaking hue identity, while adjusting an RGB channel produces a less predictable color shift. Runtime CSS math — modern browsers support `hsl(from var(--primary) h s calc(l + 10%))` to derive theme tokens at render time. Designer cognition — designers raised on HSV color pickers reason about color in hue + chroma terms even when the file ships hex. **HSL's problem** is that its Lightness axis is not perceptually uniform — a green at L=50% looks visibly brighter than a blue at L=50% because HSL inherits sRGB's gamma quirks and treats every hue as equivalent on the L scale. When you need perceptual uniformity (palette generation where every step should look equally bright, dark-mode token computation that doesn't accidentally make blue text harder to read than green text), reach for OKLCH instead — the same tool surfaces both, so the choice is one glance away.

This tool's HEX → HSL workflow is one direction of a 5-spoke family that all share the same underlying unified color converter. The dedicated unified color converter is the hub — it shows all 9 formats simultaneously editable and is the right tool when your workflow needs more than just hex and HSL. The single-direction spokes target specific Google search intents: the hex to RGB converter for the canvas-and-hardware direction, the RGB to hex converter for the inverse, the hex to OKLCH converter for modern perceptually-uniform design systems (Tailwind v4 and shadcn both default to OKLCH now), and the hex to CMYK converter for print-prep approximations. All five spokes and the hub share the same parsing engine and the same conversion math, so the results are guaranteed identical across the family. Every conversion runs locally in your browser — your hex codes are never uploaded, never logged, and zero network requests fire as you type. Verify in DevTools.

// Convert a hex color string to {h, s, l, alpha} per CSS Color 4 §6.4
// h in 0-360, s and l in 0-1, alpha in 0-1.
function hexToHsl(input) {
  let h = input.trim().replace(/^#/, '');
  if (h.length === 3 || h.length === 4) h = h.split('').map(c => c + c).join('');
  const r = parseInt(h.slice(0, 2), 16) / 255;
  const g = parseInt(h.slice(2, 4), 16) / 255;
  const b = parseInt(h.slice(4, 6), 16) / 255;
  const alpha = h.length === 8 ? parseInt(h.slice(6, 8), 16) / 255 : 1;
  const max = Math.max(r, g, b), min = Math.min(r, g, b), delta = max - min;
  const L = (max + min) / 2;
  const S = delta === 0 ? 0 : delta / (1 - Math.abs(2 * L - 1));
  let H = 0;
  if (delta !== 0) {
    if (max === r) H = ((g - b) / delta) % 6;
    else if (max === g) H = (b - r) / delta + 2;
    else H = (r - g) / delta + 4;
    H = (H * 60 + 360) % 360;
  }
  return { h: H, s: S, l: L, alpha };
}

console.log(hexToHsl('#3b82f6')); // { h: 217, s: 0.91, l: 0.60, alpha: 1 }

Key Features

All Five Hex Shapes Parsed Identically

3-digit `#F73`, 4-digit alpha `#F738`, 6-digit `#3b82f6`, 8-digit alpha `#FF573380`, plus the no-`#` variant for each. The parser normalizes all of them into the same internal color before deriving HSL, so you can paste whichever shape your source uses without manually expanding shorthand first. Capitalization is also normalized — `#3b82f6` and `#3B82F6` produce identical HSL output.

HSL Output in Modern Space-Separated Syntax

The HSL field surfaces the value in CSS Color 4's modern form: `hsl(217 91% 60%)` for opaque colors, `hsl(217 91% 60% / 0.5)` for alpha-bearing ones. Both shapes work in every evergreen browser (Chrome 65+, Safari 13+, Firefox 52+). The legacy comma form `hsl(217, 91%, 60%)` is one mechanical replace away if your target needs it; the modern syntax is preferred in new code because it aligns with CSS Color 4's other functional syntaxes.

OKLCH Source-of-Truth, Not HSL Pivot

Even though this spoke targets HEX → HSL specifically, the shared underlying converter holds the canonical color as an OKLCH triple internally. This means HEX → HSL → RGB → OKLAB → HEX round-trips without per-step float drift; legacy converters that route through HSL as their pivot accumulate rounding error and can drift the hue by several degrees over a few conversions. OKLCH-pivot keeps every other format mathematically anchored to the same source point.

Alpha Channel Decoded Cleanly

8-digit and 4-digit hex with alpha (`#RRGGBBAA` and `#RGBA`) are parsed correctly. The trailing pair maps to a 0-1 alpha float: `00` → 0, `80` → 0.502, `FF` → 1. The output uses CSS Color 4's slash syntax (`hsl(217 91% 60% / 0.5)`) by default; the legacy `hsla(217, 91%, 60%, 0.5)` form is one replace away. Useful for design-token migration where alpha values may have been buried in 8-digit hex codes.

Eight Other Formats Visible Simultaneously

The same hex you paste also drives RGB, HSV, HWB, OKLCH, OKLAB, CMYK, and the closest CSS named color — all visible at a glance on the same page. You're never locked into hex → HSL only. If a teammate needs the OKLCH triple for a Tailwind v4 token (where perceptual uniformity matters more than HSL's gamma-quirky L), the closest named color for documentation prose, or the RGB tuple for a canvas call, the values are already there with their own Copy buttons.

WCAG + APCA Contrast Built In

Pass a hex through and the contrast row immediately scores it against both white and black using WCAG 2.1 (regulatory floor: 4.5:1 for body text, 7:1 for AAA) and APCA Lc (proposed WCAG 3 successor: target `|Lc| ≥ 75` for body text). Useful when you've just converted a brand hex to HSL and want to verify the resulting color (or a lightness-adjusted variant) is actually readable as a body-text color before shipping it.

Copy as CSS / Tailwind v4 / SwiftUI / Compose / Flutter

Below the picker, the Copy as code section turns the current color into ready-to-paste snippets for five platforms: CSS custom property (`--color-brand: hsl(217 91% 60%)`), Tailwind v4 `@theme` token, SwiftUI `Color(hue:saturation:brightness:)` literal, Jetpack Compose `Color.hsl(217f, 0.91f, 0.60f)` constant, Flutter `HSLColor.fromAHSL(...)`. The exact syntax each platform expects, ready to drop into an iOS asset catalog, Android theme file, or Flutter `ThemeData`.

100% In-Browser — No Upload, No Tracking

All hex parsing, HSL conversion, contrast scoring, and palette generation runs locally in your browser. Your hex codes are never transmitted, never logged on any server, never analyzed. Zero network requests as you type — verify in DevTools. Safe for unannounced brand palettes, internal design tokens, draft mockups under NDA, and any other confidential color work.

Shareable URL Hash for the Exact Color

The current color encodes into the URL hash as `#hex=3b82f6` automatically on every change. Copy the URL, paste into a Slack thread or a GitHub issue, and anyone who opens it lands on the same hex with the same HSL triple. The hash lives only in your address bar and is never transmitted to the server (browsers don't include URL fragments in HTTP requests), so even sharing the link doesn't leak the color to any third party.

Hex to HSL Converter Alternatives

RapidTables Hex to HSL

browser tool

The default Google result for "hex to hsl" — a single-direction form with hex in, HSL out, no other formats visible. Useful for one-off lookups when arriving from search. Lacks OKLCH, contrast checking, gamut detection, alpha handling, and the multi-format simultaneous view. This tool wins on every axis except the bare-bones single-conversion case.

ColorHexa

browser tool

Long-running per-color SEO pages with deep metadata: conversions, palettes, harmonies, gradients for any hex you query. UI is dated (early-2010s), no OKLCH support, no APCA contrast, no wide-gamut handling. Strong for SEO discovery of a specific hex via Google; weaker for active conversion workflows where typing into a unified-field UX is faster.

W3Schools HSL Calculator

browser tool

Beginner-friendly HEX/RGB/HSL toggle on a teaching-focused page, ubiquitous in search results. No OKLCH, no alpha handling beyond hsla, no advanced features. Useful as a reference next to W3Schools' explainer content. This tool wins on every other axis: more formats, perceptual math, gamut + contrast + CVD features, modern code export for Tailwind v4 / SwiftUI / Compose / Flutter.

Browser DevTools Color Picker

built-in browser feature

Chrome, Firefox, and Safari DevTools all ship a color picker that toggles between HEX, RGB, and HSL inline when you click a color swatch in the CSS pane. Free, no install, always available. Lacks OKLCH, lacks shareable URLs, lacks code-export for non-web platforms (SwiftUI, Compose). Reach for DevTools when you're already debugging CSS; reach for this tool when you need cross-platform output.

HSL Color Picker by Mothereff

browser tool

A focused HSL picker with live hue/saturation/lightness sliders and a hex output. Minimal UI, good for quick HSL exploration. Lacks OKLCH and the broader format grid; no contrast or gamut features. Useful as a focused HSL-only tool; this tool covers the same workflow plus 8 other format views and the perceptual checks.

ConvertingColors

browser tool

Per-color SEO pages covering many spaces (HEX, RGB, HSL, HSV, CMYK, XYZ, CIELAB). Lacks modern OKLCH support and the unified-field editing UX. Auto-generated content pages feel content-farm-ish but the conversion data is correct. Good for spelunking individual color metadata via Google; this tool is faster for active workflows.

Hex to HSL Examples

CSS variable definition for a brand color

#3b82f6

HSL output: `hsl(217 91% 60%)`. The canonical workflow for a design system built on HSL: define the brand as `--primary: hsl(217 91% 60%)` once, then compose lighter shades by adjusting only the L percentage — `hsl(217 91% 70%)` for a hover tint, `hsl(217 91% 80%)` for a disabled state, `hsl(217 91% 90%)` for a subtle background fill. Hue and saturation stay locked, so the family reads as a coherent ramp. RGB-based stylesheets need three coordinated channel edits per step; HSL needs one.

Designer translating Figma color to HSL picker

#FF5733

HSL output: `hsl(11 100% 60%)`. Designers reasoning about color in hue + saturation + lightness terms (the cognitive model Munsell formalized in 1905) often want the HSL triple even when the source-of-truth file ships hex. Hue = 11° places this on the red side of the orange wedge; saturation = 100% means the channel is fully chromatic; lightness = 60% sits a notch above the midpoint. Pasting the Figma hex once produces the matching HSL, ready to drop into the designer's mental picker without a manual color-wheel guess.

Quick lightness sweep for a palette

#3b82f6

HSL output: `hsl(217 91% 60%)`. With the HSL triple in hand, generating a tint ramp is a one-dimensional sweep: pivot L to 70% for `hsl(217 91% 70%)`, 80% for `hsl(217 91% 80%)`, 90% for `hsl(217 91% 90%)` to climb toward white; drop to 50%, 40%, 30% for darker shades. The whole 9-step ramp emerges from changing one number. Tints and shades stay tonally related because hue and saturation stay constant — the trick legacy design systems used before OKLCH made perceptually-uniform ramps cheap.

8-digit hex with alpha → hsla()

#FF573380

HSL output: `hsl(11 100% 60% / 0.5)`. The trailing pair (`80`) decodes as `128/255 ≈ 0.502`, surfaced as the alpha channel via CSS Color 4's slash syntax. The equivalent legacy form is `hsla(11, 100%, 60%, 0.5)`, which has been supported in every browser since IE 9 and is what older preprocessors expect. 8-digit hex with alpha shipped natively in evergreen browsers in 2018; before that, alpha had to come through the `hsla()` function explicitly.

Common Hex → HSL Conversions

Reference table of the 10 most-converted hex codes and their HSL equivalents — pure primaries, pure secondaries, and two real-world brand colors from the Tailwind palette.

Black

#000000 hsl(0 0% 0%)

Pure black. Lightness at 0% — the absence of emitted light. Hue and saturation are conventionally 0 for grays.

#000000 hsl(0 0% 0%)

Pure black on a screen is rarely the right design choice — try `hsl(0 0% 7%)` or OKLCH lightness 0.1-0.15 for softer body text.

Need perceptually-uniform output instead? Try the dedicated hex to OKLCH converter — every L step looks equally bright across hues, unlike HSL.

White

#FFFFFF hsl(0 0% 100%)

Pure white. Lightness at 100% — the brightest possible sRGB color. Hue and saturation are conventionally 0 for grays.

#FFFFFF hsl(0 0% 100%)

Pure white backgrounds can produce eye strain in dark environments — try `hsl(0 0% 98%)` or OKLCH 0.98 for warmer alternatives.

Need perceptually-uniform output instead? Try the dedicated hex to OKLCH converter — every L step looks equally bright across hues, unlike HSL.

Red

#FF0000 hsl(0 100% 50%)

Pure red. Hue at 0° (the wheel's starting position), saturation fully chromatic, lightness at the midpoint where pure hues live.

#FF0000 hsl(0 100% 50%)

Pure red is highly saturated and rarely fits a brand palette — most "red" brand colors sit closer to `hsl(0 73% 50%)` (#DC2626).

Need perceptually-uniform output instead? Try the dedicated hex to OKLCH converter — every L step looks equally bright across hues, unlike HSL.

Green

#00FF00 hsl(120 100% 50%)

Pure green. Hue at 120° (one third of the way around the wheel), saturation fully chromatic, lightness at 50%. CSS named color `lime`.

#00FF00 hsl(120 100% 50%)

CSS keyword `green` resolves to #008000 (hsl(120 100% 25%)), not #00FF00 — a frequent source of confusion. Use `lime` for pure hsl(120 100% 50%).

Need perceptually-uniform output instead? Try the dedicated hex to OKLCH converter — every L step looks equally bright across hues, unlike HSL.

Blue

#0000FF hsl(240 100% 50%)

Pure blue. Hue at 240° (two thirds of the way around the wheel), saturation fully chromatic, lightness at the midpoint.

#0000FF hsl(240 100% 50%)

Pure blue on a white background fails WCAG AA contrast (3.7:1) — consider `hsl(224 76% 48%)` (Tailwind blue-700) for body text.

Need perceptually-uniform output instead? Try the dedicated hex to OKLCH converter — every L step looks equally bright across hues, unlike HSL.

Cyan

#00FFFF hsl(180 100% 50%)

Cyan. Hue at 180° (the midpoint of the wheel, opposite red), saturation fully chromatic, lightness at the pure-hue midpoint. CSS named color `cyan` or `aqua`.

#00FFFF hsl(180 100% 50%)

Cyan sits opposite red on the wheel (180°/0°), making it the natural complementary harmony partner for any red-family brand color.

Need perceptually-uniform output instead? Try the dedicated hex to OKLCH converter — every L step looks equally bright across hues, unlike HSL.

Magenta

#FF00FF hsl(300 100% 50%)

Magenta. Hue at 300° (five sixths around the wheel), saturation fully chromatic, lightness at the pure-hue midpoint. CSS named color `magenta` or `fuchsia`.

#FF00FF hsl(300 100% 50%)

Magenta sits opposite green on the wheel (300°/120°), making it the natural complementary harmony partner for any green-family brand color.

Need perceptually-uniform output instead? Try the dedicated hex to OKLCH converter — every L step looks equally bright across hues, unlike HSL.

Yellow

#FFFF00 hsl(60 100% 50%)

Yellow. Hue at 60° (one sixth around the wheel, between red and green), saturation fully chromatic, lightness at the pure-hue midpoint.

#FFFF00 hsl(60 100% 50%)

Yellow at hsl(60 100% 50%) looks much brighter than red at hsl(0 100% 50%) — a vivid example of HSL's perceptual non-uniformity. OKLCH normalizes this.

Need perceptually-uniform output instead? Try the dedicated hex to OKLCH converter — every L step looks equally bright across hues, unlike HSL.

Tailwind blue-500

#3b82f6 hsl(217 91% 60%)

Tailwind CSS's default blue-500 brand color — the canonical "web blue" of the mid-2020s. Used in countless dashboards, marketing sites, and admin tools.

#3b82f6 hsl(217 91% 60%)

Tailwind v4 redefines blue-500 in OKLCH (`oklch(0.629 0.193 263.4)`) for perceptually-uniform ramps — HSL is the v3 fallback.

Need perceptually-uniform output instead? Try the dedicated hex to OKLCH converter — every L step looks equally bright across hues, unlike HSL.

Tailwind rose-500

#f43f5e hsl(350 89% 60%)

Tailwind CSS's default rose-500 — a high-saturation pink-red used commonly for accent buttons, alert states, and brand contrast.

#f43f5e hsl(350 89% 60%)

Rose-500's hue (350°) sits just before red (0°/360°) on the wheel — a slight pink shift that reads as warmer than pure red.

Need perceptually-uniform output instead? Try the dedicated hex to OKLCH converter — every L step looks equally bright across hues, unlike HSL.

How to Use the Hex to HSL Converter

  1. 1

    Paste a hex code into the HEX field

    Drop any hex value into the HEX input — with or without the leading `#`, in 3-digit shorthand (`#F73`), 6-digit full form (`#3b82f6`), 4-digit alpha shorthand (`#F738`), or 8-digit alpha full form (`#FF573380`). The tool normalizes all five input shapes to the same canonical color internally. Capitalization doesn't matter (`#3b82f6` and `#3B82F6` parse identically). Invalid characters or wrong digit counts produce a quiet inline error; valid hex updates every other format field in real time, including HSL.

  2. 2

    Read the HSL triple from the HSL field

    The HSL field below the HEX field shows the matching `hsl()` value in CSS Color 4's modern space-separated syntax: `hsl(217 91% 60%)` for an opaque color, `hsl(217 91% 60% / 0.5)` for an alpha-bearing one. Hue is an integer degree from 0 to 360; saturation and lightness are integer percents from 0 to 100. The values are rounded for display readability — the tool's internal OKLCH source-of-truth means the underlying precision is float, so round-trips back to hex stay stable.

  3. 3

    Click Copy to grab the HSL string

    Each format card has a Copy button on the right. One click and the value lands on your clipboard — the button label briefly flashes "Copied!" so you know. The copied string is the canonical CSS Color 4 syntax (`hsl(217 91% 60%)`); if your target needs the legacy comma form (`hsl(217, 91%, 60%)`), the conversion is mechanical. For platform-specific output (Tailwind v4, SwiftUI, Compose, Flutter), use the Copy as code section below the picker — those snippets emit the format each platform expects natively.

  4. 4

    Also visible: RGB, OKLCH, OKLAB, HSV, HWB, CMYK, named color

    The same hex you paste lights up the other format fields too — RGB for canvas calls and hardware, OKLCH and OKLAB for perceptually-uniform design systems, HSV and HWB for designer color-picker workflows, CMYK for print estimates, and the closest CSS named color for documentation prose. You're never locked into hex → HSL only. If you also need the OKLCH triple for a Tailwind v4 `@theme` block (where perceptual lightness matters more than HSL's gamma-quirky L), it's right there in the OKLCH field with its own Copy button.

  5. 5

    Use the picker to sweep lightness visually

    Below the format grid is an SL square + hue slider + alpha slider for visual exploration. The SL square maps directly to HSL's Saturation × Lightness plane: drag vertically to walk L from 0% to 100% while watching the HSL field update in real time. Useful for generating a tint or shade visually before locking in the exact percentage. On Chromium browsers (Chrome, Edge, Brave) the EyeDropper button activates the native `EyeDropper` API for sampling any pixel on screen, including outside the browser.

Common Hex / HSL Mistakes

Assuming HSL Lightness Is Perceptually Uniform

A green at `hsl(120 100% 50%)` looks visibly brighter than a blue at `hsl(240 100% 50%)`, even though both are at L=50%. Generating tint ramps by sweeping L produces uneven-looking results across hues — the green ramp's light end climbs faster than the blue ramp's. This is a structural property of HSL inheriting sRGB's gamma quirks, not a bug in your code. For perceptually-uniform ramps, switch to OKLCH.

✗ Wrong
Sweep HSL L for a 9-step palette:
hsl(120 100% 50%) and hsl(240 100% 50%) at the same L
Look visibly different in brightness — palette feels uneven.
✓ Correct
Sweep OKLCH L instead:
oklch(0.7 0.2 130) and oklch(0.7 0.2 250)
Look equally bright; palette reads coherent across all hues.

Forgetting Hue Wraps at 360°

HSL hue is angular — `hsl(370 91% 60%)` is interpreted as `hsl(10 91% 60%)` because 370° mod 360° = 10°. Animating hue from 350° to 380° wraps cleanly through 360°/0° (a thin sliver of red), but interpolating linearly from H=350 to H=10 the wrong way takes the *long* path through cyan, green, yellow — 320° of detour. Use `Math.min(diff, 360 - diff)` to pick the short path, or use a color library's built-in hue interpolation.

✗ Wrong
Linear interpolation from H=350 to H=10:
(350 + 10) / 2 = 180° (cyan midpoint)
Wrong — goes the long way around the wheel.
✓ Correct
Short-path hue interpolation:
midpoint = ((350 + 10 + 360) / 2) % 360 = 0° (red midpoint)
Goes through red, the short path around the wheel.

Confusing HSL With HSV

HSL and HSV share the hue axis but differ in their third axis. HSL's Lightness is symmetric — 0% black, 50% pure hue, 100% white. HSV's Value is asymmetric — 0% black, 100% pure hue, white only when Saturation drops to 0. `hsl(0 100% 100%)` is white; `hsv(0 100% 100%)` is pure red. Many color libraries and design tools (Photoshop's HSB picker, Sketch's color panel) use HSV — copying values between the two systems without converting produces wildly different colors.

✗ Wrong
Paste HSV values from Photoshop into a CSS hsl() rule:
Photoshop HSB 0, 100, 100 (pure red)
CSS hsl(0 100% 100%) renders as white — wrong color entirely.
✓ Correct
Convert HSV → HSL before pasting into CSS:
HSV 0, 100, 100 → HSL 0, 100%, 50%
CSS hsl(0 100% 50%) renders as pure red — correct.

Dropping the Percent Signs in HSL

HSL's S and L axes require the `%` suffix in CSS — `hsl(217 91 60)` is a parse error in every browser; the correct form is `hsl(217 91% 60%)`. Only Hue is dimensionless (its unit is degrees, but the suffix is optional). Many ad-hoc converters forget to emit the percent signs in their HSL output, producing invalid CSS that silently fails when pasted. The tool always emits the percent signs in the HSL field.

✗ Wrong
Emit HSL without percent signs:
hsl(217 91 60)
CSS parse error — every browser ignores the entire rule.
✓ Correct
Emit HSL with percent signs on S and L:
hsl(217 91% 60%)
Valid CSS — works in every evergreen browser and IE 9+.

Who Uses Hex to HSL

Frontend Devs Defining HSL CSS Variables
Define `--primary: hsl(217 91% 60%)` once from the Figma hex, then compose `--primary-hover: hsl(217 91% 70%)`, `--primary-active: hsl(217 91% 50%)`, `--primary-bg: hsl(217 91% 95%)` by adjusting only the L number. Paste the hex once, read the HSL triple, drop into the CSS custom property block. The pattern that legacy design systems used to keep tints and shades tonally coherent before OKLCH-based ramps took over.
Designers Translating Hex to HSL Picker
Designers raised on hue + saturation + value pickers (Adobe, Sketch, Figma's HSB mode) often want the HSL triple even when the source file ships hex. Pasting the hex once produces the matching HSL, ready to read into the designer's mental color-wheel position without a manual guess. Helpful when reviewing a brand color spec and wanting to know where it sits on the hue wheel relative to other brand colors in the family.
Theme System Authors Computing Dark-Mode Tokens
Dark-mode theming often inverts L while keeping H and S — a light-mode `hsl(217 91% 60%)` primary maps to a dark-mode `hsl(217 91% 40%)` (or similar). Paste the light-mode hex, read the HSL, compute the dark-mode L, write the new HSL back into the dark theme token. The pattern is mechanical when you have the HSL triple; it's much fiddlier to do with raw RGB channels.
Design-System Authors Generating Tint and Shade Ramps
Generate a 9-step tint/shade ramp by sweeping L: `hsl(217 91% 95%)` (lightest), 85%, 75%, 65%, 55%, 45%, 35%, 25%, `hsl(217 91% 15%)` (darkest). Paste the base hex, read the HSL, sweep L in 10% steps mentally or in code. (For perceptually-uniform ramps where every step looks equally bright, switch to the OKLCH field next door — HSL ramps look uneven across hues because L isn't perceptually uniform.)
CSS Authors Using Runtime hsl(from ...) Math
Modern CSS supports `color-function-from` syntax: `hsl(from var(--primary) h s calc(l + 10%))` derives a lighter variant of `--primary` at render time, without precomputing every step. Paste the brand hex, confirm the HSL triple, drop the base into a CSS variable, and use the runtime math for derived tokens. Ships in Chrome 119+, Safari 17.2+, Firefox 128+.
Frontend Devs Building Tailwind v3 HSL Token Sets
Tailwind v3 stored theme colors as space-separated HSL triples in CSS variables (`--primary: 217 91% 60%`), composed via `hsl(var(--primary))` in `tailwind.config.js`. Paste the brand hex, read the HSL, drop the three numbers (without the `hsl(...)` wrapper) into the variable definition. Tailwind v4 has since pivoted to OKLCH-first, but v3 codebases still use the HSL pattern and will for years.
Color-Picker UI Authors Mapping Hex to HSL Controls
Building a color picker that exposes hue / saturation / lightness as three separate sliders (the classic Adobe-style UI) means mapping an incoming hex onto the picker's three controls. Paste the hex here, read the HSL triple, position the three sliders programmatically. The conversion is the same one your picker would run internally; this tool surfaces the intermediate values for debugging.
Accessibility Engineers Adjusting Brand Color Lightness for Contrast
When a brand color fails WCAG contrast against a background, the cheap fix is to bump L until the ratio clears — without changing H or S, the color still reads as the same brand identity. Paste the brand hex, watch the contrast badges, mentally adjust L (or use the picker's L axis) until both WCAG and APCA pass. The HSL field surfaces the new L percent for the spec doc; the hex field surfaces the matching code for the stylesheet.

Hex to HSL Math & Parsing

HEX → RGB → HSL Is a Two-Step Pipeline
The conversion goes through RGB as an intermediate. Step one: parse hex to RGB integers via `parseInt(hex.slice(1, 3), 16)` per channel. Step two: normalize RGB to 0-1, compute `max`/`min`/`delta`, apply the CSS Color 4 §6.4 piecewise trig: `L = (max + min) / 2`, `S = delta / (1 - |2L - 1|)`, `H = piecewise * 60`. The two-step structure is why the tool also surfaces the intermediate RGB tuple — it's free to display and useful for debugging.
CSS Color 4 §6.4 Defines the Reference Algorithm
The W3C CSS Color 4 specification §6.4 (`rgb()` to `hsl()` algorithm) defines the canonical piecewise math: lightness as the midpoint of max and min, saturation as `delta / (1 - |2L - 1|)` (with S = 0 when delta = 0, to avoid division by zero on grays), hue as a 60-degrees-per-step trig on which channel is max. The spec also handles edge cases: pure black (`#000`) yields `hsl(0 0% 0%)` with an arbitrary 0° hue; pure white (`#FFF`) yields `hsl(0 0% 100%)` similarly; pure gray yields `hsl(0 0% 50%)`.
Hue Wraps at 360°, S and L Are Percentages
HSL's three axes have different units. Hue is an angular degree from 0 to 360 with wraparound — `hsl(370 ...)` is interpreted as `hsl(10 ...)` because angular positions wrap. Saturation and Lightness are percentages from 0% to 100%, no wraparound; out-of-range values are clamped. CSS Color 4 also accepts hue in turns (`hsl(0.6turn ...)`) or radians (`hsl(3.787rad ...)`); the tool's output uses degrees because that's the most-common form in design-tool UIs and brand-spec documents.
HSL Lightness Is NOT Perceptually Uniform
A green at `hsl(120 100% 50%)` looks visibly brighter than a blue at `hsl(240 100% 50%)`, even though both have the same nominal Lightness — because HSL inherits sRGB's gamma quirks and uses the same L scale across every hue. This is why HSL-based tint ramps look uneven (the light end of the green ramp climbs faster than the light end of the blue ramp) and why design systems have largely migrated to OKLCH for ramp generation. The tool surfaces both HSL and OKLCH so the choice is one glance away.
OKLCH Internal Source-of-Truth for Round-Trip Stability
Even though this spoke targets HEX → HSL specifically, the shared underlying converter holds the canonical color as an OKLCH triple internally. HEX → HSL → RGB → OKLAB → HEX round-trips stay bit-stable; legacy HSL-pivot converters accumulate rounding error and can drift hue by several degrees across a few conversions. OKLCH-pivot also preserves Hue as a stable axis so dragging the hue slider doesn't accidentally cross-fade through gray. Per Björn Ottosson's 2020 OKLAB paper.
Channel Encoding: 8-Bit Unsigned, sRGB Gamma-Encoded
Hex codes encode 8-bit unsigned RGB channels (0-255) in the sRGB color space defined by IEC 61966-2-1 (1996). The values are *gamma-encoded* — the relationship between channel value and perceived brightness is non-linear, following the piecewise sRGB transfer function (roughly a 2.4 exponent with a small linear segment near zero). HSL is derived directly from these gamma-encoded RGB values without any linearization step, which is the root cause of HSL's perceptual-uniformity problem. OKLCH linearizes first and then re-maps to a perceptually-uniform space; HSL does not.

Best Practices for Hex / HSL Workflows

Use Modern Space-Separated HSL Syntax in New Code
CSS Color 4's `hsl(217 91% 60%)` (space-separated) and `hsl(217 91% 60% / 0.5)` (slash for alpha) are the canonical syntaxes for code shipping in 2025 and forward. The legacy comma forms `hsl(217, 91%, 60%)` and `hsla(217, 91%, 60%, 0.5)` are still supported everywhere but are deprecated stylistically in CSS Color 4. Use the modern syntax in new stylesheets; keep `hsla()` only for IE 9-11 fallback contexts where you genuinely need legacy support.
Generate Ramps in OKLCH, Not HSL
HSL's Lightness axis is not perceptually uniform — a 9-step L sweep produces a ramp where the green steps look brighter than the blue steps at every L value. For ramps where every step should look equally bright (the default design-system ask), generate in OKLCH instead: `oklch(0.7 0.15 217)`, `oklch(0.6 0.15 217)`, etc. The tool surfaces both HSL and OKLCH for the same hex, so switching between the two is one Copy click apart.
Lock Hue and Saturation, Sweep Lightness
When using HSL for tint/shade work, change only the L number — keep H and S identical across the ramp. Hue drift (even by 5°) makes a ramp look jumbled. Saturation drift makes the light end look washed-out and the dark end look muddy. The discipline of one-axis-at-a-time is what gives HSL its design-friendly reputation; abandoning it gives you the worst of both worlds.
Prefer Hex for Source-of-Truth Tokens, HSL for Computed Variants
When you're writing a design-token spec, prefer hex (or OKLCH) as the canonical form — they're terser and fit cleanly in JSON or YAML. HSL is more useful for *derived* tokens at runtime (`hsl(from var(--primary) h s calc(l + 10%))`) than as the source-of-truth format. The two formats describe the same color; the choice is about which role the token plays in the system.
Document HSL Variants With the Base Hex
When you ship a CSS variable like `--primary-light: hsl(217 91% 70%)`, include a comment pointing back to the base hex: `/* base: #3b82f6 → hsl(217 91% 60%), light variant +10% L */`. Six months later, when someone wants to derive `--primary-lighter`, they need the base color to compute from — and HSL on its own doesn't surface that. The hex + HSL together preserve full provenance.
Use the URL Hash to Share Live Color Decisions
Every color change updates the URL hash as `#hex=3b82f6` automatically. Copy the URL into a Slack thread or GitHub issue and anyone who opens it lands on the same color with the same HSL triple. This is more reliable than pasting an HSL string in chat — recipients sometimes typo the degree or drop a percent sign when manually entering the value — and lets a design-review thread reference an exact color rather than "the blue we discussed Tuesday." The hash is never transmitted to the server.

Frequently Asked Questions

How do I convert hex to HSL?
First convert the hex to RGB integers via `parseInt(hex, 16)`, then normalize each channel to 0-1 by dividing by 255, then compute `max`/`min`/`delta` across the three channels and apply the CSS Color 4 §6.4 piecewise trig: lightness = `(max + min) / 2`, saturation = `delta / (1 - |2L - 1|)` (zero when delta is zero), hue = piecewise on which channel is max (60° per step around the wheel). `#3b82f6` parses to `rgb(59 130 246)` then converts to `hsl(217 91% 60%)`. This tool runs the full pipeline live as you type.
What is HSL color?
HSL is a cylindrical reshape of the sRGB color space into three perceptually-meaningful axes: Hue (0-360°, angular position on the color wheel — 0° red, 120° green, 240° blue), Saturation (0-100%, chromatic intensity — 0% gray, 100% fully chromatic), and Lightness (0-100%, brightness — 0% black, 50% pure hue, 100% white). Alvy Ray Smith published the derivation in 1978 to give designers a coordinate system closer to how they think about color than raw RGB channel addressing. HSL has been in CSS since 2010 (CSS3) and ships in every browser.
What is the difference between HSL and HSV?
Both are cylindrical reshapes of sRGB with identical hue axes, but they treat the third axis differently. HSL's Lightness goes from black at 0% through pure hue at 50% to white at 100% — symmetric, so `hsl(0 100% 50%)` is pure red and `hsl(0 100% 100%)` is white. HSV's Value goes from black at 0% to pure hue at 100% — asymmetric, so `hsv(0 100% 100%)` is pure red and white only appears when saturation drops to 0. HSL is more useful for design-system tint/shade ramps because the 50% midpoint marks the pure-color reference; HSV is more useful for color pickers because the saturation/value square maps cleanly to an SV picker UI.
Why use HSL over RGB?
Three reasons. First, intuitive sliders — moving L from 60% to 70% predictably produces a lighter shade of the same color; moving R from 130 to 150 produces a less predictable color shift. Second, palette generation — `hsl(217 91% 60%)`, `hsl(217 91% 70%)`, `hsl(217 91% 80%)` is a tonally-coherent tint ramp generated by changing one number; the same in RGB needs three coordinated edits. Third, runtime CSS math — modern CSS lets you compute `hsl(from var(--primary) h s calc(l + 10%))` to derive a lighter variant from a base token without precomputing every step. RGB has no such cylindrical-axis convenience.
How do I read an HSL value?
HSL has three parts in order: Hue, Saturation, Lightness. `hsl(217 91% 60%)` means hue = 217° (a clean blue, just past 240° pure-blue territory and back toward cyan), saturation = 91% (highly chromatic, almost no gray), lightness = 60% (a notch brighter than the pure-hue midpoint). Hue is the only axis without a percent suffix because it's expressed in degrees — values wrap at 360°, so `hsl(370 ...)` is identical to `hsl(10 ...)`. The slash-prefixed value at the end (if present) is alpha in the 0-1 range: `hsl(217 91% 60% / 0.5)` is the same color at 50% opacity.
Does CSS support HSL?
Yes — HSL has been in CSS since CSS3 in 2010 and ships in every browser, including IE 9. The original syntax used commas: `hsl(217, 91%, 60%)` for opaque and `hsla(217, 91%, 60%, 0.5)` for alpha-bearing. CSS Color 4 (W3C Candidate Recommendation since 2022) added the modern space-separated form: `hsl(217 91% 60%)` and `hsl(217 91% 60% / 0.5)` with slash-prefixed alpha. The hue can also be expressed in turns or radians (`hsl(0.6turn 91% 60%)` is identical to `hsl(217 91% 60%)`). Both legacy and modern syntaxes are interchangeable in all evergreen browsers.
What does the L in HSL stand for?
Lightness. The 0-100% axis that controls how bright the color appears, with 0% mapping to pure black and 100% to pure white. The midpoint (50%) is where the pure hue lives — `hsl(0 100% 50%)` is pure red, while `hsl(0 100% 25%)` is a darker red and `hsl(0 100% 75%)` is a lighter pink. Lightness is the symmetric counterpart of HSV's asymmetric Value. Note that HSL lightness is *not* perceptually uniform — a green at L=50% looks visibly brighter than a blue at L=50% because HSL inherits sRGB's gamma quirks; for perceptual uniformity, reach for OKLCH instead.
How precise is hex to HSL conversion?
The HEX → RGB step is bit-exact (`parseInt(hex, 16)` returns integers with no float involvement). The RGB → HSL step involves trig and division, so the output is a float that the tool rounds to integer degrees and integer percent for display. A round-trip HEX → HSL → HEX recovers the original hex within 1 channel unit (the rounding error from displaying H as an integer degree). For lossless work, OKLCH is a better internal format — this tool actually holds OKLCH as the source-of-truth internally, then derives HSL on display, so the round-trip stability is better than naive HSL-pivot converters.

Related Tools

View all tools →