Reading a Hex Code: Pairs, Positions and Base 16
A six-digit hex code is three numbers packed side by side. Read it in pairs from the left: the first pair is red, the second green, the third blue. Nothing in the code labels the pairs, so position is the only thing that tells a parser which channel is which — swap two pairs and you have a different colour, not a typo that software can catch.
Each pair is a two-digit number in base 16. The left digit counts sixteens and the right digit counts ones, with the letters A to F standing in for ten to fifteen. Case makes no difference, so #c8102e and #C8102E are the same HTML color code; uppercase is simply easier to read on a spec sheet. Here is #C8102E decoded one pair at a time:
- C8 — C is 12, and 12 × 16 = 192; add 8 and red is 200.
- 10 — 1 × 16 = 16; add 0 and green is 16.
- 2E — 2 × 16 = 32; add E, which is 14, and blue is 46.
- Written as CSS, the colour is
rgb(200, 16, 46).
The # is punctuation rather than part of the value. CSS insists on it, but design tools, spreadsheets and brand documents often drop it, so this converter reads codes with or without one. Source code frequently writes the same number as 0xC8102E, and the helper most libraries call hex2rgb expects the plain digits; neither form is valid inside a stylesheet. For the reverse direction, the RGB to HEX converter encodes channel values back into a code.
How Shorthand Codes Expand
Three- and four-digit codes are shorthand, and they expand by doubling every digit, never by padding with zeros. #F0A becomes #FF00AA, not #F000A0. The rule is mechanical, so a parser never has to guess, and it is also why #ABC and #A0B0C0 are unrelated colours despite looking alike.
Doubling a digit multiplies its value by 17: a lone F becomes FF, which is 15 × 17 = 255, and a lone 8 becomes 88, which is 136. Shorthand can therefore express only channel values that are multiples of 17 — sixteen levels per channel rather than 256, and 4,096 colours in total rather than more than sixteen million.
That ceiling is why most brand colours have no shorthand at all. Of the sixteen basic CSS colours in the table at the end of this page, 8 can be shortened; the rest use pairs such as 80 and C0, which are not doubled digits.
8-Digit Codes and the Alpha Channel
An eight-digit code adds a fourth pair for alpha, the opacity of the colour, and CSS places it last. #C8102E80 is red 200, green 16, blue 46 and alpha 80. The alpha pair decodes like any other — 80 is 128 — but CSS expresses opacity as a fraction, so a hex to RGBA conversion divides that byte by 255: 128 ÷ 255 is about 0.502.
So #C8102E80 becomes rgba(200, 16, 46, 0.502). In current CSS the same colour can also be written rgb(200 16 46 / 50.2%), because the Level 4 syntax lets rgb() carry alpha directly and keeps rgba() only as a legacy alias. A four-digit code follows the same path after expansion: #C80A is #CC8800AA, with an alpha of 170 ÷ 255, about 0.667.
| Alpha pair | Decimal | Opacity |
|---|---|---|
FF | 255 | 1 (100%) |
E6 | 230 | 0.902 (90.2%) |
CC | 204 | 0.8 (80%) |
B3 | 179 | 0.702 (70.2%) |
99 | 153 | 0.6 (60%) |
80 | 128 | 0.502 (50.2%) |
66 | 102 | 0.4 (40%) |
4D | 77 | 0.302 (30.2%) |
33 | 51 | 0.2 (20%) |
1A | 26 | 0.102 (10.2%) |
00 | 0 | 0 (0%) |
Only eleven of the 256 possible bytes appear here, one for each 10% step. Round percentages rarely land on an exact byte, so a tool that stores 50% writes 80 and reads it back as 50.2% — a harmless difference, but one that explains why an opacity can come back from a round trip looking slightly changed.
Why Some Hex Codes Are Rejected
A hex colour is valid only if, after an optional #, it has exactly 3, 4, 6 or 8 characters and every character is 0–9 or A–F. Everything else fails, and most failures trace back to a handful of habits:
- Letters outside A–F. G, O, I and L all turn up in hand-typed codes. The letter O in place of a zero is the most common of them, and the converter above points it out when it spots one.
- The wrong length. Five or seven digits usually means a character was dropped or doubled while copying from a PDF, and there is no safe way to guess which one went missing.
- Spaces and extra symbols. A space inside the code, a doubled ##, or a 0x prefix copied from source code all break parsing even when every digit is correct.
- Names instead of codes. CSS understands keywords such as teal or crimson, but they are names rather than hex, so they need a lookup instead of a conversion.
When a code is rejected, the HEX to RGB result keeps showing the last valid colour and the field explains what is wrong, so you can fix one character instead of retyping the whole value.
Why Design Tools Disagree by One
Decoding is exact, so if two applications show different numbers after a HEX to RGB conversion, the difference was introduced somewhere else. Three causes account for nearly all of it.
- Floating-point storage.Many tools keep channels as fractions between 0 and 1 — Figma's plugin API describes colours that way. Storing 200 as 0.784 and reading it back is fine, but an edit such as a blend or a brightness change can land between two whole numbers, and each tool rounds that in its own way.
- Colour management.An eyedropper samples what is on screen after the document has been converted to the monitor's profile, and a screenshot may carry a display profile of its own. Sample the same colour from a screenshot and from the source file and the readings can differ by a few levels.
- Other scales. Some pickers show channels as percentages, and high-bit-depth editors such as Photoshop in 16-bit mode keep far more than 256 levels per channel. Bringing either back to 0–255 involves rounding, which is enough to move a value by one.
The practical rule is to treat the hex code as the source of truth and copy it, rather than retyping numbers read off a picker. If a value has to pass through several tools, compare the final result with the original code.
From a Web Code to a Print Reference
Knowing that #C8102E is rgb(200, 16, 46) tells you what a screen should display, not what a printer should put on paper. When a colour that started life in a stylesheet has to appear on packaging or signage, it needs a print reference, and there are two kinds to choose from.
For a spot ink, the HEX to Pantone converter ranks the closest Pantone Matching System colours and shows how each looks on coated and uncoated paper. If you already hold a PMS number, the Pantone to HEX lookup returns its screen value from our library. For four-colour process work, the HEX to CMYK converter gives a starting build and lists what to send a printer alongside it.
New to spot colour? What Pantone is and how PMS numbers work covers the system in plain terms, and our step-by-step guide to matching a hex code to Pantone walks through the judgement calls no converter can make for you.
HEX to RGB for the 16 CSS Named Colours
Every browser recognises these sixteen keywords, whose values were fixed in HTML 4 and carried unchanged into the W3C list of CSS named colours. The table decodes each one and gives its shorthand where one exists.
| Keyword | HEX | Shorthand | RGB | As percentages |
|---|---|---|---|---|
| black | #000000 | #000 | rgb(0, 0, 0) | rgb(0%, 0%, 0%) |
| silver | #C0C0C0 | none | rgb(192, 192, 192) | rgb(75.3%, 75.3%, 75.3%) |
| gray | #808080 | none | rgb(128, 128, 128) | rgb(50.2%, 50.2%, 50.2%) |
| white | #FFFFFF | #FFF | rgb(255, 255, 255) | rgb(100%, 100%, 100%) |
| maroon | #800000 | none | rgb(128, 0, 0) | rgb(50.2%, 0%, 0%) |
| red | #FF0000 | #F00 | rgb(255, 0, 0) | rgb(100%, 0%, 0%) |
| purple | #800080 | none | rgb(128, 0, 128) | rgb(50.2%, 0%, 50.2%) |
| fuchsia | #FF00FF | #F0F | rgb(255, 0, 255) | rgb(100%, 0%, 100%) |
| green | #008000 | none | rgb(0, 128, 0) | rgb(0%, 50.2%, 0%) |
| lime | #00FF00 | #0F0 | rgb(0, 255, 0) | rgb(0%, 100%, 0%) |
| olive | #808000 | none | rgb(128, 128, 0) | rgb(50.2%, 50.2%, 0%) |
| yellow | #FFFF00 | #FF0 | rgb(255, 255, 0) | rgb(100%, 100%, 0%) |
| navy | #000080 | none | rgb(0, 0, 128) | rgb(0%, 0%, 50.2%) |
| blue | #0000FF | #00F | rgb(0, 0, 255) | rgb(0%, 0%, 100%) |
| teal | #008080 | none | rgb(0, 128, 128) | rgb(0%, 50.2%, 50.2%) |
| aqua | #00FFFF | #0FF | rgb(0, 255, 255) | rgb(0%, 100%, 100%) |
The percentage column is an older CSS form that predates hex being universal: gray can be written rgb(50.2%, 50.2%, 50.2%). It is also where rounding creeps back in, because half of 255 is 127.5, and a browser has to settle on a whole channel value before anything reaches the screen.