PixelTools
All articles
Guides5 min readby the PixelTools team

Why HEX to HSL and Back Changes Your Color

Converting HEX to HSL and back can shift a color by up to 5 steps per channel. See why it happens, real examples, and how to avoid it.

Why the color changes after a round trip

HEX to HSL and back changes a color because HSL values are usually rounded to whole numbers, and whole-number HSL cannot name every HEX color. Convert #1E90FF to HSL and you get hsl(210, 100%, 56%). Convert that back and you get #1F8FFF, not #1E90FF. Two channels are off by one step out of 255, which is invisible to the eye but fails an exact string match in a design token file, a diff, or a brand-color check. Nothing is broken. The conversion math is exact; the rounding is where the information is lost. The limit comes from whole-number HSL itself, so any converter that prints integer HSL runs into it.

Why whole-number HSL can't hold every HEX color

There are more HEX colors than whole-number HSL colors. A six-digit HEX code has 256 values per channel, so 256 x 256 x 256 = 16,777,216 colors. Whole-number HSL has 360 hues, 101 saturation values (0 to 100), and 101 lightness values, so at most 360 x 101 x 101 = 3,672,360 combinations. Several HEX colors must share one HSL label. When you convert back, you land on one specific HEX from that group, and it is often a neighbor of the one you started with. Going the other way is cleaner: an HSL value always maps to exactly one HEX code, so the loss only shows up when you go HEX to HSL and back.

Real examples, checked against the tool

These results come from running the Color Picker's own conversion code. #1E90FF becomes hsl(210, 100%, 56%) and returns as #1F8FFF. #3A7BD5 becomes hsl(215, 65%, 53%) and returns as #397AD5. #FF5733 becomes hsl(11, 100%, 60%) and returns as #FF5833. Some colors survive: #808080 becomes hsl(0, 0%, 50%) and returns as #808080, and pure green #00FF00 (hsl(120, 100%, 50%)) also returns intact. But survival is not guaranteed for greys: #7F7F7F becomes hsl(0, 0%, 50%) too and returns as #808080. Note the default blue the tool opens with, #1E90FF, is itself one of the colors that moves.

How big is the drift, across all colors?

Small, but common. We ran every one of the 16,777,216 six-digit HEX colors through the Color Picker's whole-number HSL conversion and back. Only 1,775,570 of them (about 10.6%) came back identical. The rest changed, and the largest error on any single channel was 5 out of 255. Small shifts are not visible on screen, but a shift of 5 can matter if you are matching a color against a spec or testing for equality. The takeaway is practical: treat the drift as a data integrity problem, not a visual one. Your eyes will not catch it, but a script comparing strings will.

How to avoid it

Keep one format as the source of truth and copy from it, never from a chain of conversions. If your brand color is #1E90FF, store the HEX and derive HSL only when you need to tweak lightness. Do not paste the HSL back into a file as the new original. If you author in HSL, CSS itself accepts decimals, such as hsl(210.4 100% 55.9%), so you can keep more precision than integers allow. Pick the format once, convert once, and compare colors as RGB numbers instead of strings. In the Color Picker, the three fields all derive from one stored RGB value, so copying HEX, RGB, or HSL from the same color is always consistent with each other.

What the Color Picker accepts and rejects

The tool reads HEX as 3 or 6 digits, with or without the #, so #abc expands to #AABBCC. It does not read 8-digit HEX or any alpha value, so #1E90FF80 is rejected. RGB can be rgb(30, 144, 255) or just 30 144 255. Decimals are rounded, so 30.6 becomes 31. Values outside 0 to 255 are rejected, not clamped, so 300,0,0 changes nothing. Percent RGB and the space-and-slash syntax rgb(30 144 255 / 50%) are not accepted. HSL saturation and lightness must be 0 to 100 or the input is rejected. Hue is not rejected: it wraps around the color wheel, so 450 acts like 90. When input is invalid, the color stays as it was and a hint appears under the field.

When HSL is still the right choice

HSL is still the better format when you want to adjust a color by hand. Raising lightness lightens it, lowering saturation mutes it, and changing hue rotates it, and none of that is obvious from a HEX code. The rounding only matters when you treat an HSL value as a stored copy of a HEX color. For hover states, tints, and quick experiments, a one-step drift is irrelevant. Use HSL to explore, then settle on a final value and store it in the format your codebase already uses. If you need a quick conversion in either direction, type or paste into the Color Picker and the other fields update at once.

Frequently asked questions

Try it on PixelTools — free, no upload needed