Design FIELD NOTES · 4 MIN READ
Hex, RGB, and HSL: The Three Color Formats Explained
The same color written three ways: hex packs channels into base-16 digits, RGB lists them plainly, and HSL splits color into hue, saturation, and lightness.
One orange, three addresses: #ff8000, rgb(255, 128, 0), and hsl(30, 100%, 50%) all describe exactly the same color. Converting between them is not a matter of taste — it is fixed arithmetic, and knowing what each format is good for is most of practical color work on the web.
The same color, written three ways
A hex code packs the red, green, and blue channels into six hexadecimal (base-16) digits, two per channel. Each pair decodes as first × 16 + second, so ff = 15 × 16 + 15 = 255, 80 = 8 × 16 = 128, and 00 = 0 — giving rgb(255, 128, 0). RGB is the same information as plain decimal numbers, one per channel from 0 to 255. HSL re-describes the color as a hue angle (0–360° on the color wheel), a saturation percentage, and a lightness percentage. Nothing is added or lost between the three: they are notations, not different colors.
What each format is for
Hex is the compact, canonical form — design tools, eyedroppers, and design tokens speak it, and six characters survive a Slack message intact. RGB exposes the raw channels, which is what pixel-level code wants: canvas getImageData returns 0–255 numbers, image libraries compare channels, and rgba() attaches an alpha value. HSL is the authoring format, because its three dials map to what humans adjust: spin the hue to change the color's identity, drop the saturation to mute it, slide the lightness to darken it. Browsers parse all three into the same internal value, so the choice is about your workflow, not the rendering.
How the converter computes HSL from RGB
Hex-to-RGB is the direct base-16 decode above. HSL is derived with the standard sRGB algorithm: normalize each channel to 0–1, take the strongest and weakest channel (max and min), then lightness is (max + min) / 2. Saturation depends on how far apart they are, with the formula switching at the midpoint: d / (2 − max − min) when lightness is above 0.5, otherwise d / (max + min), where d = max − min. Hue comes from which channel wins: it measures how far green and blue sit from the red axis, wrapping around the wheel. For #ff8000: max = 1 (red), min = 0, so lightness = 0.5 and d = 1, making saturation 1 / 1 = 100%; with red dominant, hue = (0.502 − 0) / 1, scaled around the wheel to ≈30°. Result: hsl(30, 100%, 50%).
Details the converter handles for you
Input is forgiving. The leading # is optional, uppercase hex is accepted and normalized to lowercase on output, and both 3-digit and 6-digit forms parse. RGB input tolerates spaces around the commas ("255, 128, 0") but rejects values above 255, since a channel physically cannot exceed that. One subtlety worth knowing: the 3-digit shorthand duplicates each digit, so #f80 expands to #ff8800 — rgb(255, 136, 0) — which is a different color from #ff8000, not an abbreviation of it. The converter shows a live swatch beside the values, so you confirm the color you meant is the color you got.
Where HSL earns its keep
Once a color is in HSL, the hue number is a coordinate on the 360° wheel — the same wheel that color harmonies rotate around to build palettes. Lightness is the axis that tints and shades slide along, which is why a hover state is usually just "same hue, different lightness" expressed in one HSL number. Hex and RGB can do all of this too, but each edit means recomputing three unrelated-looking numbers; HSL keeps the dial you care about isolated.
Try it yourself
The Color Converter accepts either a hex code or an RGB triplet and instantly returns all three formats with a swatch. If you always start from hex, the Hex to RGB Converter is the one-field version of the same pipeline. And when you do not have a code at all, the Color Picker lets you choose visually and hands back hex, RGB, and HSL plus a coordinating palette.