Design · 7 min read
Understanding Web Colour: HEX, RGB, HSL and How to Convert
Why the same colour has so many notations, what each one is good for, how to read a HEX code at a glance, and a few practical rules for choosing accessible colour pairs.
By The Utylo team · Published April 24, 2026
A single colour on the web can be written half a dozen ways, and a designer trying to pin down a particular shade of teal will eventually meet all of them. #008080, rgb(0, 128, 128), hsl(180, 100%, 25%), and oklch(54.97% 0.0855 196.97) are the same pixel. They look identical on screen, behave identically in CSS, and yet each notation exists for a reason. This guide walks through what each format actually encodes, how to read one at a glance, when to convert between them, and the handful of practical rules that keep colour choices accessible rather than merely pretty.
Why one colour has so many names
Every colour your screen can display is ultimately three numbers — how much red, green, and blue light each subpixel emits. That is the only thing the hardware understands. The various notations are different ways of writing those three numbers down, optimised for different humans. HEX is compact and copy-pasteable. RGB is what programmers reach for when they want to do arithmetic. HSL is laid out the way designers actually think about colour. The newer formats — HWB, LCH, OKLCH — try to fix problems with the older ones around perceptual uniformity and wide-gamut displays. The browser converts whichever you give it back to red, green, and blue before lighting up the pixel.
HEX: three bytes in disguise
A HEX colour is six hexadecimal digits, optionally preceded by a hash. The six digits split into three pairs: the first pair is red, the second is green, the third is blue. Each pair is one byte, so it encodes a value from 00 (no light) to FF (255, full light). #FF0000 is full red with no green or blue. #000000 is black. #FFFFFF is white. #808080 is grey at roughly half intensity on each channel.
The shorthand form is three digits rather than six, and each digit is treated as if it were doubled. #FFF means #FFFFFF, not some half-strength white. #F0A is #FF00AA. The shorthand only works when each pair has two identical digits, which is why #FA3 is fine but #F1A3B5 cannot be shortened. Eight-digit and four-digit forms exist as well, with the extra pair encoding alpha: #FF000080 is red at roughly 50% opacity.
Reading a HEX code at a glance
Once you know the structure, a HEX code tells you a surprising amount without any conversion at all. Look at each pair in turn:
- The first pair is the red channel.
FFis full red,00is none,80is half. - The second pair is green. Green is the channel humans are most sensitive to, so it dominates how bright a colour looks.
- The third pair is blue, the channel we are least sensitive to.
With practice this becomes second nature. #3366CC is clearly a mid-blue: low red, mid green, high blue. #CC9933 is just as clearly a warm gold: high red, mid green, low blue. You do not need to memorise hex values, only the rough mapping that 0 is none, 8 is half, and F is full.
RGB and RGBA: the same numbers, in decimal
rgb(255, 0, 0) and #FF0000 are the same colour. RGB is simply the decimal version of what HEX writes in base 16. The advantage is that the numbers are easier to manipulate: if you want a colour 10% redder, you can add to the first channel and trust the result. The disadvantage is that the notation is verbose and that rgb(180, 47, 92) tells you almost nothing about what the colour will look like until you mentally convert it.
RGBA adds an alpha channel as a fourth value between 0 (transparent) and 1 (opaque): rgba(255, 0, 0, 0.5) is half-transparent red. Modern CSS also accepts a single-argument form with a slash — rgb(255 0 0 / 0.5) — and treats rgb and rgba as synonyms when an alpha value is present. Both styles work; pick one and be consistent.
HSL and HSLA: the designer's notation
HSL stands for hue, saturation, and lightness, and it describes colours the way humans actually talk about them. Hue is an angle from 0 to 360 degrees around a colour wheel — 0 is red, 120 is green, 240 is blue, and the rest of the spectrum sits between. Saturation is a percentage from 0 (grey) to 100 (fully saturated). Lightness is a percentage from 0 (black) to 100 (white), with 50 being the "pure" version of the hue.
The reason designers favour HSL is that you can adjust one dimension at a time and get the change you expect. To make a colour darker, drop the lightness. To make it more muted, drop the saturation. To shift it towards orange, nudge the hue. With HEX or RGB, the same adjustments require changing all three numbers in coordinated ways. A palette of related colours is trivial to build in HSL: keep the hue and saturation fixed and step the lightness through a sequence.
The catches are real but small. HSL's lightness is not perceptually uniform — a yellow at 50% lightness looks far brighter than a blue at 50% lightness — and two colours with the same lightness value can have very different apparent contrast. For most UI work, this rarely matters; for serious palette design, it matters a lot, and OKLCH is the better tool.
HWB and OKLCH: the modern alternatives
CSS Colors Level 4 brought several new notations into browsers. Two are worth knowing about.
HWB(hue, whiteness, blackness) is HSL's simpler cousin. The hue works the same way, then you add a percentage of white and a percentage of black. hwb(0 0% 0%) is pure red; hwb(0 50% 0%) is pink; hwb(0 0% 50%) is a dark red. It is genuinely easier to reason about than HSL for tints and shades, and is worth trying.
OKLCH is the one to learn next. It uses lightness, chroma, and hue, but in a colour space designed to be perceptually uniform — equal numerical changes produce equal-looking changes regardless of hue. It also reaches into wide-gamut colours that sRGB cannot represent, so it is the right notation for designs that need to look correct on modern displays. The syntax is oklch(60% 0.15 250): lightness, chroma (think saturation, but better-behaved), and hue in degrees. If you are starting a new design system today, build it in OKLCH and translate to HEX only at the boundary.
Converting between formats
Some conversions are trivial; others are best left to a tool.
RGB to HEX is just decimal-to-hex, one channel at a time. 255 is FF, 128 is 80, 0 is 00. rgb(255, 128, 0) becomes #FF8000. You can do this in your head with practice, but there is no reason to.
HSL to RGB is mathematically straightforward but fiddly — there is a piecewise function based on which 60-degree segment of the hue circle you are in, with several intermediate values. Nobody does this by hand, and you should not start. The same is true in reverse, and doubly true for OKLCH, which involves a matrix transform through an intermediate colour space.
For everyday work, paste the value into the RGB to HEX Converter or pick a fresh colour with the Colour Picker, both of which show every notation side by side. The colour picker is also the fastest way to discover what a HEX code actually looks like when you cannot quite picture it.
What CSS minifiers do with colour
CSS minifiers will rewrite colour values to whatever is shortest. The common transformations:
#FFFFFFshrinks to#FFFwhen the pairs repeat.rgb(255, 0, 0)becomes the named colourred, which is shorter still.#000000becomes#000, and in some contexts the named colourblack.- Whitespace inside
rgb()andhsl()functions is removed.
These changes are all safe — the resulting CSS is bit-for-bit equivalent — and they add up across a stylesheet. The CSS Minifier applies them automatically.
Choosing accessible colour pairs
A colour palette that looks fine to you may be unreadable to a sizeable fraction of your audience. The Web Content Accessibility Guidelines define a contrast ratio between text and background, expressed as a number from 1:1 (identical, invisible) to 21:1 (pure black on pure white). The thresholds worth memorising are:
- 4.5:1 for body text. Below this, normal-sized text becomes hard to read for users with mild vision loss.
- 3:1 for large text (roughly 18pt and up, or 14pt bold) and for non-text elements like icons and form borders.
- 7:1 if you want to meet the stricter AAA standard, which is sensible for long-form reading.
"Looks fine on my screen" is not a meaningful test. Your screen is probably brighter than average, in a darker room than average, with younger eyes than average. Measure the ratio.
Hue alone is not enough
Roughly 8% of men and 0.5% of women have some form of colour vision deficiency, most commonly difficulty distinguishing red from green. Any interface that conveys information through hue alone — a red error state and a green success state with no other cue — will fail those users. Pair colour with a shape, an icon, or a text label. Use contrast in lightness, not just hue, to separate adjacent regions of a chart. This is not a niche concern; it is most of the reason accessibility audits flag colour problems at all.
Why the same colour looks different on different screens
A HEX value is a request, not a guarantee. The actual colour your screen produces depends on its colour gamut (the range of colours it can physically display), its calibration, the ambient light in the room, and the colour profile the operating system is applying. A modern phone with a wide-gamut OLED panel will render #FF0000 as a more vivid red than a cheap office monitor from 2014. Neither is wrong; they are doing the best they can with different hardware.
For most web work, sRGB is the safe assumption — it is what browsers target by default and what almost every screen can at least approximate. If you are designing for print, photography, or high-fidelity brand work, you need to think about colour profiles seriously. For a marketing site or a product UI, sticking to sRGB and testing on a couple of representative devices will get you 95% of the way there.
A short checklist
- Use HEX for static values in your codebase — it is the most compact and most widely recognised.
- Use HSL or OKLCH when you are building a palette or generating related shades programmatically.
- Always include alpha when a colour is meant to overlay something else — implicit white backgrounds bite eventually.
- Run every text-on-background pair through a contrast checker. 4.5:1 for body text, 3:1 for large text and UI elements.
- Never rely on hue alone to communicate state.
- Convert with a tool, not in your head — the maths is not hard, but getting it slightly wrong is easy and silent.
Colour on the web is a thin layer of mathematics over a thick layer of human perception, and the notations all exist because no single one is good at every job. Pick the one that fits the task, lean on the Colour Picker and RGB to HEX Converter when you need to move between them, and let the contrast ratio be the thing that decides whether a pairing is good enough.
Tools mentioned in this guide
More guides
Images
How to Compress Images for the Web Without Losing Quality
A practical guide to image compression: which format to choose, what quality level to use, when to resize before compressing, and how to keep type-heavy images from turning to mush.
Developer
A Practical Guide to JSON: Formatting, Validating and Converting
JSON is everywhere, but it is easy to get wrong. A field guide to the syntax that trips people up, the difference between formatting and validation, and how to safely convert between JSON and CSV.
Privacy & Security
How to Create Strong Passwords (and Why Length Beats Complexity)
What actually makes a password strong in 2026, why the old advice about special characters is misleading, and how to use a password generator without falling into common traps.