HEX, RGB and HSL: understanding colour codes
Three notations for the same colours — and when each one earns its keep.
Open any stylesheet and you’ll meet the same colour written three different ways:
#3366ff, rgb(51, 102, 255) and hsl(225, 100%, 60%).
They all paint the exact same pixel. What changes is how the number is built — and
once you understand the structure of each one, you can read a colour off the screen, tweak it
by hand, and build a palette without guessing. Let’s take them in turn.
HEX: red, green and blue in base 16
A HEX code is a screen colour written as red, green and blue channels in hexadecimal (base
16). The canonical form is #RRGGBB: two hex digits each for red, green and blue.
Each pair runs from 00 to FF, which is 0 to
255 in everyday decimal. So #000000 is pure black (all channels off),
#FFFFFF is white (all channels at full), and #FF0000 is full-strength
red with no green or blue.
Two shorthands are worth knowing. #RGB is a three-digit form where each digit is
doubled — #39F expands to #3399FF — handy when every channel happens
to use a repeated digit. And #RRGGBBAA adds a fourth pair for alpha
(opacity): #3366FF80 is that blue at roughly 50% opacity, because 80
in hex is 128, about halfway to 255.
RGB: the same channels, in plain decimal
rgb(r, g, b) describes exactly the same three channels as HEX, just written in
decimal from 0 to 255 instead of hex pairs. #3366FF and
rgb(51, 102, 255) are the identical colour — 33 hex is 51,
66 hex is 102, and FF hex is 255. The
decimal form is easier to reason about arithmetically, which is why code that mixes or
interpolates colours usually works in RGB.
To add opacity you use rgba(r, g, b, a), where the alpha is a fraction from
0 (fully transparent) to 1 (fully opaque): rgba(51, 102, 255,
0.5). Modern CSS also lets you write the alpha directly inside rgb() with a
slash — rgb(51 102 255 / 50%) — so the separate rgba() keyword is no
longer strictly necessary.
HSL: the one built for humans
HSL describes a colour the way a person thinks about one. Instead of three light channels, it uses hue, saturation and lightness:
Hue — 0 to 360°
The position on the colour wheel, in degrees. Red sits at 0°, green at 120°, blue at 240°, and it wraps back to red at 360°.
Saturation — 0 to 100%
How vivid the colour is. 0% is a flat grey; 100% is the purest, most intense version of that hue.
Lightness — 0 to 100%
How light or dark it is. 0% is always black, 100% is always white, and 50% is the “full” colour.
This split is why HSL is so pleasant for editing. Want the same colour but darker? Drop the lightness and leave hue and saturation alone. Need a warmer variant? Nudge the hue a few degrees. Building a palette of related colours is just a matter of holding saturation and lightness steady while rotating the hue — something that is fiddly and error-prone in HEX or RGB, where every shift touches all three numbers at once.
How they convert
HEX and RGB are trivially interchangeable: each HEX pair is simply a channel value written in
base 16, so converting is just changing the number base. CC in hex is
12 × 16 + 12 = 204 in decimal, and 204 back to hex is CC.
HSL is a genuine transformation rather than a re-spelling — the conversion maps the
red/green/blue cube onto a cylinder of hue, saturation and lightness — but it is exact and
loss-free in both directions for opaque colours. The table below shows one colour in all three.
| Notation | Value | What each part means |
|---|---|---|
| HEX | #3366FF | R=33, G=66, B=FF (hex pairs) |
| RGB | rgb(51, 102, 255) | R=51, G=102, B=255 (0–255) |
| HSL | hsl(225, 100%, 60%) | hue 225°, fully saturated, 60% light |
You rarely need to do this by hand. Paste any of the three formats into the colour converter and palette builder and it shows you the other notations instantly, plus harmonious palettes built around your colour. It runs entirely in your browser.
Alpha, opacity and why contrast matters
Alpha controls transparency rather than colour: it decides how much of whatever sits
behind an element shows through. A button at rgba(0, 0, 0, 0.6) looks
different over a white card than over a photo, because the final colour is a blend. That blend
is also why semi-transparent text is risky — its effective contrast depends on the background
it lands on.
Contrast is the difference in brightness between text and its background, expressed as a
ratio from 1:1 (identical, invisible) to 21:1 (pure
black on pure white). The Web Content Accessibility Guidelines set thresholds that good
designs should meet:
| Level | Normal text | Large text (≈18.7px bold or 24px+) |
|---|---|---|
| WCAG AA | 4.5:1 | 3:1 |
| WCAG AAA | 7:1 | 4.5:1 |
A pairing can look fine to you and still fail — light grey on white is a classic offender — which is why the ratio is worth measuring rather than eyeballing. Drop your foreground and background colours into the contrast checker to see the live ratio and whether it clears AA or AAA before you ship.
Related tools: Colour tools · Contrast checker