Guide
HEX vs RGB vs HSL
Three ways of writing the same colour. They can express the same things; where they differ is in what they make easy.
#3498db, rgb(52, 152, 219) and hsl(204, 70%, 53%) are the same colour. Any of them will render identically in any browser. None of them is more correct than the others, so the useful question is which one lets you do the next thing without thinking.
They describe the same space differently
HEX and RGB are the same coordinates in different bases. Both say how much red, green and blue light the pixel emits. HEX writes each channel as two base-sixteen digits, RGB writes them as decimal numbers. Converting between them is pure notation: nothing is gained, lost or reinterpreted.
HSL is a genuine re-description of the same point. It keeps the colour identical but addresses it by hue angle, saturation and lightness instead of by three light levels. The conversion is reversible, so no information is lost, but the axes now line up with the way people talk about colour.
HEX: for carrying a colour
Hex is the transport format. It is short, unambiguous, has no spaces or commas to get mangled, and every tool understands it. When you paste a colour into a message, a config file or a design tool, hex is almost always right.
Its weakness is editing. Making #3498db ten percent lighter requires changing all six digits, and there is no way to do it in your head. Hex works well as a container and badly as a working format.
It has two forms worth knowing. Three digits is shorthand where each digit doubles, so #39c means #3399cc; it only works when both digits of every pair already match. Eight digits adds an alpha byte: #3498db80 is that blue at about half opacity.
RGB: for computing with a colour
RGB is what you want when a colour is an input to arithmetic. Blending two colours, computing a luminance, averaging a region of an image and writing a shader all operate on channels, and decimal channels are easier to reason about than hex pairs.
Its weakness is that the axes do not match perception. There is no "make it lighter" direction in RGB. Adding 20 to every channel does lighten a colour, but it also desaturates it, because the gap between the largest and smallest channel shrinks in relative terms. Reduce the channels of a saturated red toward each other and it washes out rather than darkening cleanly.
There is a subtler trap. The numbers are not linear in light. sRGB applies a transfer curve of roughly 2.2, so the midpoint of the scale is not the midpoint of perceived brightness. Averaging two colours channel by channel gives a result that is darker than the colour halfway between them looks. Any code that needs physically correct blending has to linearise first, which is exactly what a contrast calculation does.
HSL: for editing a colour
HSL is the working format. Its three numbers are the three questions a designer asks:
- Hue, 0 to 360 degrees around the colour wheel. Red at 0, yellow near 60, green at 120, cyan at 180, blue at 240, magenta at 300, back to red at 360.
- Saturation, 0 to 100 percent. Zero is grey; 100 is as colourful as that hue gets at that lightness.
- Lightness, 0 to 100 percent. Zero is black, 100 is white, and 50 is where hues are at their most vivid.
This makes systematic work easy in a way the other two do not. A hover state is the same colour with lightness reduced by ten. A set of tints for backgrounds is the same hue and saturation at 95, 90 and 85 percent lightness. A complementary accent is the same colour with 180 added to the hue. Every one of those is a single-number change.
HSL has two known weaknesses. Lightness is not perceptual: hsl(60, 100%, 50%) is a brilliant yellow while hsl(240, 100%, 50%) is a very dark blue, despite both claiming 50 percent lightness. And saturation behaves oddly at the extremes, where a large change in the number produces almost no visible change.
What about HSV?
HSV (also written HSB) shares the hue axis with HSL but replaces lightness with value, which is simply the largest of the three channels. In HSV, 100 percent value with 100 percent saturation is the pure hue; in HSL, that is 50 percent lightness. HSV maps neatly onto a square picker, which is why nearly every colour picker in every design application is built on it. HSL maps more neatly onto the idea of a colour ramp, which is why stylesheets tend to use it.
And the newer ones?
CSS now also supports lab(), lch(), oklab() and oklch(). These fix HSL's biggest flaw: in OKLCH, equal changes in lightness look like equal changes, and hue stays put when you adjust lightness, so a ramp built in OKLCH does not drift toward purple the way an HSL ramp of a blue can.
They are worth learning if you build colour systems. For sampling a colour out of a picture and using it, the three older notations still cover everything, and they are what the rest of your toolchain will expect.
Practical rules
- Store and share in hex. It is the shortest and most portable form, and the least likely to be corrupted in transit.
- Compute in RGB. And linearise first if the maths needs to be physically meaningful.
- Edit in HSL. Then convert back to hex when you are done.
- Do not round-trip repeatedly. Displayed HSL is rounded to whole degrees and percentages, so converting back and forth can drift a unit at a time. Keep the hex as the source of truth.
The converter will move a value between all of them in one step, and the hex picker shows what each pair of digits is contributing while you edit.