The Complete Guide to Color Formats on the Web
Every color you see on a screen is the same underlying thing: three numbers describing how hard the red, green, and blue subpixels are driven. Everything else — hex codes, rgb(), hsl(), tomato, an eyedropper readout in Figma — is notation layered on top of those three numbers, invented to make them easier for some particular audience to read or manipulate. Understanding that one fact removes most of the confusion around web color formats, because it reframes the question from "which format is correct?" to "which notation is most convenient for what I am doing right now?"
This guide covers the formats you will actually encounter in CSS, design handoffs, and image tooling: HEX and its shorthand and alpha variants, RGB, HSL, HSV/HSB, the CSS named colors, and how transparency is encoded in each. It also covers the conversion math, so that when a converter hands you a number you know why it is that number. If you are looking for guidance on contrast and readability rather than notation, our Complete Guide to Accessible Color and Contrast covers that territory in depth.
Every converter linked here runs entirely in your browser. Unreleased brand palettes and client color values never leave your machine.
RGB: The Model Everything Else Describes
RGB is additive: start from black and add light. Each of the three channels runs from 0 (off) to 255 (fully on), giving 256³ = 16,777,216 possible colors — the "16.7 million colors" figure on old monitor boxes. All three channels at 0 is black, all three at 255 is white, and equal values across all three always produce a neutral gray.
In CSS, RGB has two legal spellings:
color: rgb(255, 87, 51); /* legacy comma syntax */
color: rgb(255 87 51); /* modern space-separated syntax */
color: rgb(100% 34% 20%); /* percentages, 0-100% per channel */
The modern space-separated form is what CSS Color Level 4 standardized, and it is what browsers serialize back to you when you read a computed style. Percentages and 0-255 integers are interchangeable; the browser maps both onto the same internal value.
RGB's advantage is arithmetic. Blending two colors, interpolating a gradient, applying a tint, or averaging the pixels of an image are all straightforward per-channel operations. That is why nearly every graphics library, canvas API, and image format works in RGB internally regardless of what notation you typed in your stylesheet.
Its disadvantage is that the numbers are not intuitive. Given rgb(52, 152, 219), almost nobody can tell you what it looks like, and "make it 20% darker" requires touching all three channels by different absolute amounts to preserve the hue.
HEX: The Same Numbers in Base 16
A hex code is RGB written in base 16. Nothing more. #RRGGBB splits into three pairs, each pair a two-digit hexadecimal number from 00 (0) to FF (255):
#FF5733
FF = 15×16 + 15 = 255 → red
57 = 5×16 + 7 = 87 → green
33 = 3×16 + 3 = 51 → blue
= rgb(255, 87, 51)
Two hex digits cover exactly 0-255, which is why the pairing is so tidy — one byte per channel, two digits per byte. That neatness is the entire reason hex became the web's default color notation. You can run the conversion by hand, or paste a value into a HEX to RGB converter and get the decimal triple instantly. Going the other direction, an RGB to HEX converter does the same in reverse.
Hex has three forms in modern CSS:
- 6-digit
#RRGGBB— the standard form, all 16.7 million colors. - 3-digit
#RGBshorthand — each digit is doubled, so#F0Cmeans#FF00CCand#333means#333333. Only 4,096 colors can be written this way, because both digits of each channel must match. - 8-digit
#RRGGBBAA— adds an alpha byte at the end.#FF573380is that same orange at0x80= 128/255 ≈ 50% opacity. A 4-digit#RGBAshorthand also exists and expands the same way.
Hex codes are case-insensitive: #ff5733 and #FF5733 are identical. Teams usually pick one convention and lint for it. If you need to normalize a mixed pile of values — expanding shorthand, unifying case, catching typos like a five-character code — run them through the HEX code validator rather than eyeballing them. The mechanics of how hex maps to channel intensity are worth internalizing; how hex color codes actually work walks through the base-16 arithmetic step by step.
HSL: Color Described the Way People Think
HSL restates the same sRGB space in cylindrical coordinates, chosen so that each axis corresponds to something a human can articulate.
- Hue — 0-360 degrees around a color wheel. 0 is red, 120 green, 240 blue, wrapping back to red at 360.
- Saturation — 0-100%. 0% is fully gray; 100% is the most vivid version available at that lightness.
- Lightness — 0-100%. 0% is black and 100% is white regardless of hue or saturation. The pure hue lives at 50%.
color: hsl(204, 70%, 53%); /* same blue as #3498DB */
color: hsl(204 70% 53%); /* modern space-separated syntax */
The payoff is that intent maps directly onto a single number. A hover state 10% darker is hsl(204, 70%, 43%). A muted variant is a saturation change. A full set of tints and shades for a design system is one hue held constant while lightness steps. None of those operations have an obvious equivalent in hex, which is why hex-based palettes tend to be assembled by hand in a design tool and pasted in as opaque constants.
HSL also makes relationships between colors legible. Complementary colors are 180 degrees apart; a triadic scheme is three hues 120 degrees apart. Reading a stylesheet full of HSL values tells you something about the palette's structure. Reading one full of hex codes tells you nothing. Convert an existing palette with the HEX to HSL converter and the structure of a palette someone else built often becomes visible immediately.
The catch: HSL lightness is a geometric construct, not a perceptual one. hsl(60, 100%, 50%) (yellow) and hsl(240, 100%, 50%) (blue) claim identical lightness, but the yellow is dramatically brighter to the eye. Stepping lightness uniformly across different hues produces a palette that looks uneven even though the numbers are regular. This is the specific problem oklch() was designed to fix.
HSV/HSB: The Model in Your Design Tool
HSV — also called HSB, where Brightness and Value mean the same thing — shares HSL's hue axis but redefines the other two. Value is the maximum of the three RGB channels: how bright the brightest channel is. Saturation is measured against that maximum rather than against a midpoint.
The consequence is that the two models disagree wherever saturation is not 0 and the third component is not at a shared reference point:
| Color | HSL | HSV |
|---|---|---|
| Pure red | hsl(0, 100%, 50%) |
hsv(0, 100%, 100%) |
| White | hsl(0, 0%, 100%) |
hsv(0, 0%, 100%) |
#4080BF |
hsl(210, 50%, 50%) |
hsv(210, 67%, 75%) |
Note the trap in the last row: hsv(210, 50%, 50%) is not #4080BF — it is #406080, a distinctly darker, duller blue. Identical numbers, different colors. Photoshop, Figma, and most color pickers expose HSB, while CSS only speaks HSL, so numbers copied across that boundary without conversion are a recurring source of "the color looks wrong in the browser" bug reports. HSL vs HSV covers exactly where the two models diverge and how to convert safely.
Named Colors
CSS defines 148 color keywords. The original alphabetical list runs from aliceblue to yellowgreen and contains 147 names; CSS Color Level 4 added rebeccapurple (#663399). Nine of those keywords are aliases — the seven gray/grey spelling pairs plus aqua/cyan and fuchsia/magenta — so 148 names resolve to 139 distinct colors.
color: tomato; /* #FF6347 */
color: rebeccapurple; /* #663399 */
color: darkslategray; /* #2F4F4F */
They are readable and they are exact — every keyword has a fixed hex equivalent baked into the spec — but the set is an inherited X11 palette rather than a designed one, with famously inconsistent naming. darkgray (#A9A9A9) is lighter than gray (#808080). green is #008000, not the vivid #00FF00 most people expect, which is lime. Named colors are excellent for quick prototypes, debugging outlines, and documentation examples, and a poor foundation for a product palette. CSS named colors goes through the full list and where each name is genuinely useful.
Alpha: The Fourth Component
Transparency is expressed as an alpha value where 0 is fully transparent and 1 is fully opaque. Every format has a way to carry it:
color: rgba(255, 87, 51, 0.5); /* legacy RGBA */
color: rgb(255 87 51 / 50%); /* modern slash syntax */
color: hsl(204 70% 53% / 0.5); /* HSL with alpha */
color: #FF573380; /* 8-digit hex, 0x80 = 128/255 */
In modern CSS the separate rgba() and hsla() functions are aliases of rgb() and hsl(), which now accept an optional alpha after a slash. Both spellings work everywhere.
The distinction that trips people up is alpha versus the opacity property. Alpha applies to one color — a semi-transparent background with fully opaque text on top. opacity applies to an entire element and everything inside it, and it also creates a new stacking context. They are not substitutes. Alpha channels and transparent colors covers the encoding and the practical differences.
The Conversion Math
HEX to RGB is pure parsing: split into pairs, read each as base 16.
RGB to HSL takes a few more steps. Normalize each channel to 0-1, then:
max = largest channel, min = smallest channel, d = max - min
L = (max + min) / 2
S = 0 if d == 0, else d / (1 - |2L - 1|)
H = 0 if d == 0
60 × (((g-b)/d) mod 6) if max is r
60 × (((b-r)/d) + 2) if max is g
60 × (((r-g)/d) + 4) if max is b
Run #3498DB through it: normalized channels are 0.204, 0.596, 0.859. Blue is the maximum, so L = (0.859 + 0.204) / 2 = 0.531, d = 0.655, S = 0.655 / 0.937 = 0.699, and H = 60 × (((0.204 - 0.596) / 0.655) + 4) = 204. The result is hsl(204, 70%, 53%).
HSL to RGB reverses this through a chroma value, and HSV substitutes V = max with S = d / max. In practice you will use a converter rather than doing this by hand — the all-in-one color value converter shows every format for a single input at once, which is the fastest way to sanity-check a value you are unsure about.
One thing worth knowing: HEX↔RGB round-trips are exact, but anything passing through HSL or HSV can drift by a unit because the intermediate values are fractional and get rounded back to integers. Keep one canonical format in your design tokens and derive the others rather than repeatedly converting back and forth.
Choosing a Format
There is no correct answer, only fit for purpose:
- HEX — brand constants, values copied from design files, anywhere compactness and universal tool support matter. Nearly every design tool exports hex.
- RGB — values computed in JavaScript, canvas work, per-channel blending and image processing.
- HSL — design systems, hover and active states, tints and shades, any palette you want to be able to read and adjust by hand.
- HSV/HSB — inside design tools, where "pick a hue then set brightness" matches how a color picker is laid out. Convert before it reaches CSS.
- Named colors — prototypes, debug styles, documentation.
The pragmatic pattern most teams land on: define tokens once in HSL as CSS custom properties, so that derived states are one-line adjustments, and keep hex only where an external system demands it. If you inherit a stylesheet and want to know what is actually in it, a CSS color analyzer will extract and group every color value in the file. The trade-offs between the three main notations are compared directly in hex vs RGB vs HSL, and the narrower hex-versus-RGB question is covered in hex vs RGB.
What Comes After sRGB
Every format above describes a color inside sRGB, the standard gamut the web assumed for its first three decades. Modern displays exceed it, and CSS Color Level 4 added notation that can address the difference:
oklch()/oklab()— perceptually uniform. Equal lightness steps look equal across hues, which fixes HSL's biggest weakness for palette generation and gradients.lab()/lch()— the older CIE-based perceptual spaces, also device-independent.color(display-p3 1 0.2 0.1)— explicitly targets a wider gamut than sRGB.color-mix(in oklch, var(--brand) 70%, white)— blends two colors in a chosen space, natively in CSS.
Browser support for all of these is now broad. They do not replace hex and HSL — sRGB values still round-trip through every design tool, image format, and API you will touch — but for generating palettes and interpolating gradients, oklch() produces visibly better results with less manual correction.
Conclusion
Web color formats are five ways of writing the same information, each optimized for a different reader. HEX is compact and machine-friendly. RGB is the arithmetic form everything computes in. HSL is the one humans can reason about. HSV lives in your design tool and disagrees with HSL in ways that quietly cause bugs. Named colors are convenient and inconsistent. Alpha rides along in all of them, encoded as a fourth component or a trailing byte.
Pick a canonical format for your tokens, convert deliberately at the boundaries rather than by habit, and know the two or three places the models genuinely disagree. Everything else is notation — and notation you can convert with a paste and a glance.
Frequently asked questions
Is HEX a different color model from RGB?
No. HEX is a notation, not a model. #FF5733 and rgb(255, 87, 51) describe exactly the same color using exactly the same three sRGB channels — one writes them in base 16, the other in base 10. Converting between them is lossless in both directions.
Which color format should I use in CSS?
Use HEX for fixed brand tokens where you are copying values from a design file, and HSL for anything you need to reason about or derive — hover states, tints, shades, and theme variants. RGB is most useful when a value is being computed in JavaScript. All three compile to the same pixels, so consistency within a codebase matters more than the choice itself.
What is the difference between HSL and HSV?
Both use a 0-360 hue, but their second and third components mean different things. In HSL, lightness 100% is always white and 50% is the most vivid version of a hue. In HSV, value 100% is the brightest form of the hue itself and white only occurs when saturation is 0. The same numeric triple gives different colors in each model — hsl(210, 50%, 50%) is #4080BF while hsv(210, 50%, 50%) is #406080.
How many CSS named colors are there?
148 keywords. The original alphabetical list from aliceblue through yellowgreen contains 147 names, and CSS Color Level 4 added rebeccapurple. Nine of those names are aliases (gray/grey pairs plus aqua/cyan and fuchsia/magenta), so they resolve to 139 distinct values.
How does the alpha channel work in a hex code?
An 8-digit hex code (#RRGGBBAA) puts alpha in the final two digits, on the same 00-FF scale as the color channels. 00 is fully transparent and FF is fully opaque, so #FF573380 is rgb(255, 87, 51) at roughly 50% alpha, since 0x80 is 128 out of 255.
Does converting between color formats lose quality?
HEX and RGB are interchangeable with no loss because they store identical integers. HSL and HSV round-trips can drift by a unit or two, because the conversion produces fractional values that get rounded back to 0-255 integers. Store one canonical format in your design tokens and convert on the way out rather than repeatedly round-tripping.
What is the difference between 3-digit and 6-digit hex codes?
A 3-digit code is shorthand where each digit is duplicated: #F0C expands to #FF00CC. It can only express colors whose channel pairs are both identical digits, which is 4,096 of the 16,777,216 possible sRGB colors, so most real colors need the full 6 digits.
Should I be using oklch() instead of HEX and HSL?
For new work involving gradients, palette generation, or programmatic lightness steps, oklch() is a genuine improvement because its lightness axis matches human perception, so equal steps look equal. HEX, RGB and HSL remain the right choice for interoperability with design tools, exported assets, and anything that must round-trip through file formats that only understand sRGB.
Try the related tools
HEX to RGB Converter
Convert HEX color codes (#RRGGBB, #RGB) to RGB / RGBA values.
RGB to HEX Converter
Convert RGB / RGBA color values to 6-digit or 8-digit HEX codes.
HEX to HSL Converter
Convert HEX color codes to Hue, Saturation, and Lightness (HSL).
All-in-One Color Value Converter
Convert simultaneously across HEX, RGB, RGBA, HSL, HSLA, HSV, CMYK, and HWB formats.