Free & Private Online Browser Utility

Color Converter: Hex to RGB, RGB to HSL

One field takes a colour written any of the ways CSS writes it, and hands back the other three plus the declarations you would paste into a stylesheet. The hex and RGB strings are exact restatements of the same integers, so nothing is lost travelling between them. HSL is different: hue, saturation and lightness are whole numbers in CSS, so an HSL string is a rounded portrait of your colour rather than a copy of it. This page does not paper over that. It parses the rounded string back on its own, compares the result with the colour you started from, and tells you the distance in channel units — for the colour currently in the box, not for some average case.

How to use

  1. Step 1: Write the colour the way you found it

    Paste #02e4e6, 02E4E6, rgb(2, 228, 230), rgba(18, 52, 86, 0.5), rgb(2 228 230 / 0.5), hsl(181, 98%, 45%) or a #abc short form into the field. Parsing is case-insensitive, the hash is optional on hex, and the swatch under the field updates on every keystroke, so you can also start from the Pick control and let the browser write the value for you.

  2. Step 2: Read the three notations side by side

    Hex, RGB and HSL each get a row with its own copy button, and a chip next to the value names which notation your input was read as — the difference between a colour you typed in HSL and one that merely looks like it. The channel bars spell out the three integers and their percentage of 255, which is the number a canvas or shader API wants.

  3. Step 3: Check the rounding notice before you copy HSL anywhere

    The panel under the output re-parses the HSL string printed above it. When that returns a different colour it names the difference; when it returns the same colour it says so. Copy the hex or RGB row when a value has to survive the trip, and the HSL row when a person is going to adjust the colour afterwards.

Options explained

Colour field

Accepts #RGB, #RGBA, #RRGGBB and #RRGGBBAA with the hash optional, six bare hex digits, and rgb(), rgba(), hsl() and hsla() in both the comma form and the space-and-slash form. Channels may be integers or percentages; hue may carry a deg unit, be negative, or exceed a full turn.

When to use: Use it for anything you can copy out of a devtools panel, a design inspector or a config file. Colour names are the exception and the error line says so rather than guessing at a value.

Pick (native colour swatch)

The operating system's own colour picker, opened by clicking the swatch. It writes a six-digit hex value and preserves whatever alpha the field already carried.

When to use: Fastest route to a starting colour when you have no value yet. System pickers work in whole 0-255 channels, which is exactly what the parser stores, so nothing rounds on the way in.

Alpha slider

Sets transparency from fully see-through to solid in one-percent steps. It rewrites the field in decimal notation, because 0.5 written as a decimal stays 0.5, while 0.5 written as the hex byte pair 80 reads back as 0.502.

When to use: Adjusting a token's opacity without touching its channels. The slider is disabled while the field holds something unparseable, so a typo cannot silently produce a transparent colour.

Try row

Six inputs that each exercise a different branch of the parser, including the colour the build-time measurement reports as the worst HSL rounding case in the whole cube.

When to use: Loading one of them is a quick way to see how the page treats a short hex, a percentage channel, a slash-separated alpha and a legacy four-comma rgba() — the four shapes people paste most often.

Worked example

Input: #02e4e6

Output: hsl(181, 98%, 45%) — and rgb(2, 223, 227) once that string is parsed back

The default colour on the page is the first one the exhaustive measurement finds whose HSL form is as far from its colour as an HSL form can get: pasting hsl(181, 98%, 45%) into the field returns #02dfe3, five units of 255 below the green channel you typed. Enumerating all 16,777,216 colours on every build puts 108 colours at that distance, 15,103 at four units, and 1,775,045 with no movement at all. One unit is the ordinary outcome.

Tips & limits

  • Copy hex or RGB into anything that has to match a value exactly — a design token, a test fixture, a PNG's palette entry. HSL is the notation to copy when the next step is a human changing the colour, because lightness behaves the same way at every hue.
  • A three-digit hex is not an abbreviation of a longer value: each digit is doubled, so #abc means #aabbcc. Only 4,096 of the cube's colours can be written that way, which is why short hex shows up in hand-authored CSS and never in a picker.
  • Percentage channels round rather than truncate. rgb(50%, 0%, 100%) is 127.5 on the red channel, and this page stores 128 — so its hex reads #8000ff, not the #7f00ff you would get by cutting the fraction off.
  • Alpha travels differently in each notation. Decimal and the slash form carry the number you typed; the eight-digit hex form carries a byte pair, which is a coarser grid. The notice beside the hex row names the value that comes back.
  • The address bar carries the colour, so a link to this page with ?color=... opens on the same swatch. That is the whole state: no rows, no files and no history leave the tab.

Common problems

The parser refuses the value and the error says it found two channels.

The two syntaxes are being mixed. rgb(18 52 86, 0.5) puts spaces between the channels and a comma in front of the alpha, and the splitter reads the comma version, so it sees one blob and one number. Pick one form: rgb(18 52 86 / 0.5) or rgba(18, 52, 86, 0.5).

The colour you pasted back from the HSL row is a shade off the original.

That is the rounding the notice reported, not a mistake in the conversion. Whole degrees and whole percentages cannot describe every colour exactly; the notice states the gap for the colour in your field, and the hex row is the value to copy when the gap is unacceptable.

A name pasted from a stylesheet, such as rebeccapurple, is refused.

By design: this page converts between notations, and a name is a lookup into CSS's keyword list rather than an arrangement of the same digits. Look the name up once, then bring the hex value here — it will split into channels, percentages and an HSL form that you can adjust.

Frequently Asked Questions (FAQ)

Does this hex to RGB converter work offline once the page is loaded?

Yes. The parser and the three formatters are plain JavaScript in the page bundle, and no request is made when you type. After the document has loaded, a colour pasted into the field produces output with the network off — nothing is sent anywhere, because there is no endpoint involved in the conversion.

Why does converting to HSL lose information?

CSS writes hue as a whole number of degrees and saturation and lightness as whole percentages, so a colour whose channels do not happen to land on those steps is printed as its nearest representable HSL triple. Parsing that triple back rebuilds a colour within a few steps of 255 rather than the exact one. The notice under the output computes the distance for the colour you are looking at, by feeding its own HSL string back through the parser.

How large can the difference between a colour and its HSL form get?

Five units of 255 on a channel, measured rather than estimated. On every build a script enumerates all 16,777,216 eight-bit colours, converts each to the HSL string this page prints and parses that string again. 1,775,045 of them come back untouched; 108 are five units away on at least one channel. Hex and RGB are exact for a different reason: both are written from the three integers and read back as integers, and a lattice run over 140,608 colours taken every fifth step of each channel finds no drift at all in either form.

Which alpha syntaxes does the field accept?

Four. A fourth byte pair on hex (#RRGGBBAA), a fourth value after a comma in the legacy rgba() and hsla() forms, and a value behind a slash in the modern space-separated rgb() and hsl() forms. A hue may also be written with a deg unit or left bare; negative and over-turn values wrap around the colour wheel.

Why does my 0.5 alpha turn into 0.502 in the hex row?

Hex transparency is one byte, so alpha is stored on a 256-step grid rather than in decimals. 0.5 becomes 128 of 255, and reading 128 back out gives 0.502 in the three-decimal notation this page prints. Both numbers describe the same byte, and the gap between them is at most 0.002 anywhere in the range. If the value has to be exact in a file, keep alpha in the rgba() form.

Can it convert to CMYK, Lab or Oklch?

No, and the reason is worth knowing before you trust a converter that claims otherwise. Hex, RGB and HSL are three arrangements of the same three integers, so converting between them needs no assumptions. CMYK describes ink on a device, and Lab and Oklch describe perceptual colour spaces whose conversion depends on a white point, a rendering intent and a gamut-mapping choice. This page takes no such choices, so it offers no such output.

Why is the number of colours without a hue 622 rather than 256?

Grey is the obvious case — when all three channels match, saturation is zero and the hue slot holds a placeholder of 0. But saturation is printed as a rounded percentage, so 366 more colours sit close enough to grey that their saturation rounds to nothing and the hue in their HSL string is meaningless. That count comes out of the same exhaustive run, and it is why an HSL token copied from a near-grey colour will not survive being edited by eye.

Is my colour stored anywhere after I convert it?

Not on our side. The value lives in the field, in React state, and in the address bar query string so a link can be shared; the browser history entry is replaced rather than pushed, so typing does not leave a trail of half-typed colours behind it. There is no upload step, no analytics call carrying the value and no storage write.

Guides that cover this tool

Three names for one colour, and the one that rounds

A colour on a web page is three integers and, if you want transparency, a fourth number between zero and one. Every notation on this page is a way of writing those same four numbers, and two of the three write them exactly. The hex string prints each channel as two digits; the rgb() string prints the same integers in decimal. Both are lossless, and both are parsed from the digits rather than estimated, so what you paste is what stays.

hsl() is different, and this converter prints the difference instead of hiding it. Hue is an angle in degrees, saturation and lightness are percentages, and CSS accepts whole numbers for all three. Converting an exact colour into that notation means rounding each one, and rounding costs information. Feed the printed HSL back in and you usually get a colour very close to the one you started with — occasionally you get one that is five units of 255 away on a channel, which is the largest gap that exists anywhere in the cube.

The notice under the output is computed live, from the colour currently in the field, by parsing the HSL string this page just printed and comparing the result with the colour you typed. It is not a disclaimer. For most colours it reports a single unit of drift; for some it reports none at all, because those colours are exactly representable in whole percentages.

What the parser accepts, and what it refuses

Hex arrives in four shapes: three digits, four digits, six digits and eight digits, each with the hash optional. The three and four digit forms are CSS’s short forms, where every digit is doubled, so #abc is #aabbcc and not a truncated value. A bare six digits with no hash is accepted too, because colour pickers and design tools hand you exactly that when you copy from them.

Function notation is read in both syntaxes CSS defines. rgba(18, 52, 86, 0.5) puts the alpha in the fourth comma; rgb(18 52 86 / 0.5) puts it behind a slash with spaces between the channels. Channels may be integers or percentages —rgb(50%, 0%, 100%) is a legal colour and resolves to the same integers you would type yourself, rounding the odd half as it goes. Hue may carry a deg unit and may be negative or larger than a full turn; it wraps, because the hue wheel is a circle.

What is refused is stated in the error line rather than silently reinterpreted. Colour names are the big one: rebeccapurple is a real CSS colour with a fixed value, but converting a name into notation is a lookup table, not a conversion, and this page does only the second thing. A channel that is not a number is refused with the text that confused it, and a function with the wrong number of channels says how many it found. Five hex digits have no reading in any notation, so they are refused too rather than being padded into a colour nobody typed.

Where this fits in a stylesheet

Design tokens are usually authored in hex, consumed in rgb()and adjusted in hsl(), because the last of those is the only notation where a human can predict what changing one number will do to the appearance. Raising lightness by ten makes a colour lighter at any hue; doubling a blue channel does something that depends on what the other two channels already were. That is also why a component library in dark mode is usually the same palette with a different lightness column.

The three CSS declarations under the output are the same colour in the three notations, ready to paste into a stylesheet, a custom property or an inline style. Alpha is carried through all of them, with one honest caveat printed beside it: hex stores transparency as a fourth byte pair, and a value typed as 0.5 lands on 128 of 255, which reads back as 0.502. The decimal form is the exact one; the hex form is the compact one.

Who uses this, and for what

  • Front-end developers turning a designer’s hex token into the rgb() form a CSS custom property needs for split channels.
  • Accessibility work, where a contrast rule is written against a colour a stakeholder chose by eye and pasted as a name that is not in the stylesheet.
  • Canvas and SVG drawing code, where the same colour has to be handed to an API that takes percentages and one that takes 0–255 integers, without a second rounding step in the middle.
  • Anyone checking whether the colour in a screenshot is the colour in their code — paste the picked value, read the hex, compare the digits instead of the appearance.

Limits, stated plainly

This is a notation converter, not a colour manager. It works in the sRGB values CSS uses and does no gamut mapping, no wide-gamma or Display-P3 handling, and no colour-space conversion — oklch, lab and lch have their own algebra and a hex-to-oklch button that silently reused the HSL arithmetic would be a lie. Print colour is out of scope for the same reason: CMYK is a device description, not a rearrangement of the same three numbers. And nothing here reads a colour name, an image, or a palette file.

The colour you paste is never uploaded. It is parsed in this browser tab, and the only thing written anywhere is the address bar, which carries the value so a link you send opens on the same colour. Close the tab and there is no trace of it on our side, because there was never a request to our side in the first place.

Files never leave your device; calculations and transformations happen locally.

Last reviewed: 2026-11-03