What HEX encodes
A HEX color is a string prefixed with # that encodes red, green, and blue as pairs of hexadecimal digits. The most common form uses six characters, splitting them into three channel pairs: the first pair sets the red intensity, the second sets green, and the third sets blue. Each pair is a base-16 number from 00 (decimal 0) to ff (decimal 255), which yields 16.7 million distinct combinations.1 In that scheme #ff5500 means full red with no green and no blue, producing a saturated orange you will recognize from warning buttons and sale badges. Base 16 fits that byte structure exactly: two hexadecimal digits cover the 0 to 255 range of a single byte, which is why three channel pairs pack a full RGB color into six characters.
Shorthand notation like #f50 expands each single digit into a repeated pair, becoming #ff5500. This shorter form is only valid when both digits of each channel pair are identical, which is why #123 works but #124 does not. An optional seventh and eighth character encode the alpha channel on the same zero-to-255 scale, so #ff550080 represents that same orange at roughly 50% opacity.1 Decoding that pair structure into RGB is direct translation from base 16: ff reads as 255, 55 as 85, and 00 as 0, so #ff5500 is rgb(255, 85, 0).
TIP HEX is the most paste-friendly format for CSS, Figma, and browser DevTools, which is why designers tend to reach for it first. If you are ever unsure which color format a tool or code field accepts, pasting a six-digit HEX value is almost always a safe default that renders identically across modern browsers.
Convert RGB to HEX
Typing an rgb() or rgba() value into the RGB field
updates the HEX field at once, along with HSL, HSV, OKLCH and the nearest CSS
named color, so this direction needs no separate mode or button. Each 0 to 255
channel becomes a pair of hexadecimal digits, and the walkthrough below covers
that arithmetic, rounding for fractional channels and the eight-digit form
that carries alpha.
CSS color pickers and browser DevTools often show colors as rgb() values. Design systems, HTML attributes, and most color palettes expect #rrggbb HEX. Converting between them by hand means doing base-16 arithmetic for each channel.
How RGB to HEX conversion works
Converting RGB to HEX reverses the channel-decoding process. Each decimal integer from 0 to 255 is expressed as a two-digit base-16 number, padded with a leading zero when the value is below 16. Red channel 59 becomes 3b (3 × 16 + 11), green 130 becomes 82, blue 246 becomes f6. Concatenated with a # prefix, the result is #3b82f6.1 Building on this pattern, the conversion is lossless for any integer RGB value, and no precision is dropped when the inputs are whole numbers.
Padding matters for correctness
When a channel value is below 16, the hex representation is a single digit. The leading zero padding ensures the result is always two digits per channel, which keeps the final string exactly seven characters long (including the #). Without padding, the value 5 would serialize as "5" instead of "05", producing an invalid HEX string that no browser would parse correctly.
Zero padding also keeps the mapping between channels and string positions stable, so a parser can always locate the green pair at characters 3-4 and the blue pair at 5-6. If the red channel were allowed to collapse to a single digit, every later channel would shift position and the whole decode would break. This positional guarantee is exactly why the HEX format mandates two digits per channel and why a correct converter never skips the leading zero.
Why the reverse mapping is unique
Because each 0–255 integer maps to exactly one two-digit hex pair, the RGB-to-HEX function is injective. Two different RGB triplets can never produce the same HEX output, which means the conversion is fully reversible for integer inputs and safe to use as a cache key or a deduplication token in style systems. If you store both formats side by side in a design token file, you can index by HEX and retrieve the RGB equivalent without any ambiguity or lookup table.
Where RGB to HEX conversion comes up
Browser DevTools expose computed CSS colors in rgb() notation. Canvas APIs return pixel data as separate 0–255 integers. Color pickers in most JavaScript UI libraries emit {r, g, b} objects. Conversely, every HTML color attribute, most CSS property defaults, and nearly all design-tool import dialogs expect #rrggbb, which makes it easy to paste a DevTools color into a design file. Whenever data flows out of a browser environment into a design file, a spreadsheet, or a brand color registry, HEX is the format that copies cleanly without reformatting.
Copy-paste reliability across tools
HEX strings survive a round trip through email, Slack, spreadsheets, and version-control diffs without corruption. RGB values, by contrast, get reformatted by many tools (some add spaces, others wrap rgba() with different alpha syntax), which makes them harder to grep for across a codebase. If you need a color format that every tool in your chain understands without ambiguity, HEX is the safer choice.
When RGB input is the only option
Some APIs return only RGB. The getImageData() method on a canvas pixel buffer gives you four integers per pixel (r, g, b, a). If you are building a palette extractor or a color-theming widget, you will receive RGB values from the API and need to convert them to HEX before writing CSS custom properties or sharing the palette with stakeholders.
RGB to HEX edge cases and rounding
Integer inputs in the range 0–255 convert without loss. Values outside that range are invalid; CSS clamps them, but the resulting HEX will be incorrect.2 Floating-point RGB values, which appear frequently in libraries that store channels as 0.0–1.0, must be multiplied by 255 and rounded to integers before conversion. Alpha channels have no standard slot in 6-digit HEX, so append a seventh and eighth digit for the #rrggbbaa format, where the alpha pair uses the same 00–ff scale, with 00 fully transparent and ff fully opaque.3
Handling floating-point channel values
Libraries like Three.js and chroma.js often represent colors as normalized floats in the 0.0–1.0 range. Before converting to HEX, multiply each float by 255 and round to the nearest integer. The rounding step is critical: always rounding down (Math.floor) versus rounding to nearest (Math.round) can shift the final HEX value by one unit in either channel, which produces a visually noticeable difference on gradients.
Why out-of-range inputs break the output
If your pipeline ever produces a value below 0 or above 255, the resulting HEX string will be malformed. Negative values have no hex representation, and values above 255 require more than two digits. Validate your inputs before conversion, or clamp them explicitly, so downstream code never receives a HEX string that fails to parse. A common source of out-of-range values is arithmetic on channel values, such as boosting brightness by adding 20 to each channel without checking whether the result exceeds 255 before the conversion step.
RGB to HEX in design token pipelines
Design token systems often store colors in a format-agnostic way (as RGB objects or OKLCH coordinates) and export to multiple CSS formats at build time. When your token pipeline needs HEX output, the RGB-to-HEX conversion is the final step before writing the CSS custom property. Tools like Style Dictionary, Tokens Studio, and Theo all include HEX export as a built-in transformation.
The conversion in these tools follows the same algorithm: each 0–255 integer becomes a two-digit hex pair, padded with a leading zero for values below 16. The difference is in how they handle edge cases. Style Dictionary rounds floating-point inputs before conversion. Tokens Studio clamps out-of-range values and warns. Building on this, if you are building a custom token pipeline, decide how to handle floats and out-of-range values before the HEX conversion step, because the HEX format cannot represent fractions or values outside 0–255 per channel.
The #rrggbbaa format and browser support
CSS Color Level 4 introduced 8-digit HEX notation: #rrggbbaa, where the last two digits encode alpha on the same 00–ff scale.3 This gives you a compact way to write rgba() equivalents: #ff550080 is the same as rgba(255, 85, 0, 0.5). Browser support is excellent: Chrome 62+, Firefox 49+, Safari 10+, and Edge 79+ all parse 8-digit HEX correctly.4
Converting rgba() to #rrggbbaa requires multiplying the alpha value (0–1) by 255 and encoding it as a two-digit hex pair. An alpha of 0.5 becomes 128 in decimal, which is 80 in hex. An alpha of 1.0 becomes 255, which is ff. Building on this, the #rrggbbaa format is shorter than rgba() by several characters, which matters for large stylesheets where every byte counts. The tradeoff is readability: most developers find rgba(255, 85, 0, 0.5) easier to parse visually than #ff550080. Use the format that matches your team convention.
RGB to HEX round-trip precision in automated workflows
Automated workflows that convert RGB to HEX and back to RGB may not return the exact same values. The issue is not the HEX format itself (which is lossless for integer RGB) but the intermediate processing. If a tool normalizes RGB values to floats, converts to HEX, then converts back to RGB, the floating-point arithmetic may introduce an error of 1 in one channel.5 This is within the tolerance of human perception but can cause test failures in pixel-perfect visual regression tools.
To avoid round-trip issues in automated pipelines, store the authoritative color value in a single format (HEX or RGB) and derive the other format from it, rather than converting back and forth. If you must convert in both directions, round to the nearest integer at each step and accept that a difference of 1 in one channel is within normal floating-point tolerance. Building on this, visual regression tools like Percy and Chromatic typically allow a configurable tolerance for color differences; set it to 1–2 RGB units to avoid false positives from harmless rounding drift.
Use this when you have an RGB value from a browser DevTools color picker, a CSS computed style, or an image processing result that you need to paste into a design file or HTML attribute.
Browser DevTools color → Figma HEX
rgb(59, 130, 246)
#3b82f6
Canvas pixel data → CSS color
rgb(255, 99, 71)
#ff6347
This is the named color "tomato".
- 1.
MDN Web Docs, "<hex-color>," developer.mozilla.org, accessed June 2026. https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/hex-color
- 2.
W3C, "CSS Color Module Level 4: Color," w3.org, accessed June 2026. https://www.w3.org/TR/css-color-4/#color
- 3.
W3C, "CSS Color Module Level 4: Hex Notation," w3.org, accessed June 2026. https://www.w3.org/TR/css-color-4/#hex-notation
- 4.
Can I use, "#rrggbbaa hex color notation," caniuse.com, accessed June 2026. https://caniuse.com/css-rrggbbaa
- 5.
MDN Web Docs, "Number," developer.mozilla.org, accessed June 2026. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number
Each channel (red, green, blue) is an integer from 0 to 255. Values outside that range are invalid, and CSS clamps them, so the conversion result will be meaningless.
Type the RGB portion into the RGB field. The alpha channel does not have a standard equivalent in 6-digit HEX; for that you would need an 8-digit HEX with an alpha pair appended.
HEX (base 16) needs 16 symbols. Digits 0-9 cover the first ten; a-f cover 10-15. So ff in base 16 equals (15 x 16) + 15 = 255 in base 10, which is the maximum channel value.
No. CapyToolkit runs every RGB-to-HEX conversion locally in your browser, and the color values you type are never stored, logged, or transmitted to any server.
For whole-number RGB inputs, yes. Each triplet maps exactly to one HEX string and back, so you can safely cache the HEX output as a stable representation of that color. Floating-point inputs may lose a single unit of precision in one channel due to rounding, which is within normal tolerance but detectable by pixel-perfect visual regression tools.
Convert HSV to HEX
HSV values usually come from Photoshop's HSB panel or an operating system color picker, and the HSV field accepts them directly, filling the HEX field with the six-digit code that pastes into CSS, SVG and email HTML. Hue, saturation and value pass through RGB on the way, which is why the guide below explains the rounding you may see when that HEX code is converted back.
Photoshop and native OS color pickers use HSV.
When a designer adjusts a color in Photoshop's HSB panel and needs to hand the result to a developer, HEX is the universal transfer format: it pastes cleanly into CSS, HTML attributes, Figma color fields, and Slack messages without any reformatting. Converting HSV to HEX directly avoids the manual two-step of first converting to RGB and then converting RGB to HEX, which compounds the risk of transcription error at each step.
How HSV to HEX conversion works
Converting HSV to HEX routes through an intermediate RGB step. The HSV-to-RGB algorithm divides the hue into six 60-degree sectors and assigns intermediate chroma values to the three channels depending on which sector applies.1 Once the three 0–255 integers are computed, each converts to a two-digit hex pair: red first, green second, blue third. Concatenating those three pairs with a # prefix produces the six-character HEX string.2 Building on this, no additional precision is lost beyond the integer rounding that occurs in the HSV-to-RGB step.
Why HEX is the natural final format
HEX is the most compact universally supported color representation. Each of the three RGB channels maps to exactly two hex digits, producing a fixed-width string that any CSS parser, HTML renderer, or design tool can interpret without ambiguity.3 Because the conversion pipeline is HSV to RGB to HEX, and each step produces deterministic integer output, the final HEX value is stable: the same HSV input always produces the same HEX string, which makes it reliable for use in design tokens and automated style generation.
The CSS specification defines four hex forms, not one: #RGB, #RGBA, #RRGGBB, and #RRGGBBAA. The six-character form this tool emits is the opaque one, and appending a further two digits gives you the eight-character alpha form (where ff is fully opaque and 00 fully transparent). Hex syntax is case-insensitive, so #3b82f6 and #3B82F6 are the same color.
The single canonical string also simplifies diffing and version control. When a HEX value changes in a token file, the diff shows the exact six characters that moved, whereas an RGB triple would show three separate numbers that are harder to scan at a glance. That clarity is another reason HEX is the default storage format for design systems, and why converting HSV to HEX once at token-creation time pays off every time the value is reviewed, merged, or regenerated downstream.
Where HSV to HEX conversion comes up
Designers who work in Photoshop, macOS Color Picker, or any tool that exposes HSB fields need HEX for developer handoff. Figma's fill panel accepts HEX directly, and most design system documentation tools (Storybook, Zeroheight, Supernova) store colors as HEX strings. Furthermore, design tokens defined in Style Dictionary or Theo use HEX as the interchange format between platforms. Consequently, converting from the HSV space where a designer adjusted the color to the HEX format where it will be documented and consumed is a routine handoff step.
HEX as the interchange format between design and code
Design tools and developer tools rarely share the same color model. Photoshop speaks HSB, Figma accepts HEX, CSS uses multiple formats, and token pipelines need a single canonical representation. HEX serves as the lingua franca because it is compact, unambiguous, and supported everywhere. When a designer provides HSB values from Photoshop, converting to HEX immediately gives the developer a value they can paste into any tool without further conversion, reducing the chance that an intermediate step introduces a transcription error.
HSV to HEX edge cases and rounding
Because the conversion routes through integer RGB, the result is always a valid 6-digit HEX string: no fractional values leak into the output. HSV value 0 always produces #000000 regardless of hue or saturation. Saturation 0 at any value V produces a grey where each pair equals round(V × 255) in hex. Hue values outside 0–360 wrap modulo 360.2 Yet the intermediate integer rounding means a round-trip of HSV → HEX → HSV may return saturation or value shifted by up to 0.1 percentage points from the original coordinates.
Round-trip integrity and when it matters
The rounding error of 0.1 percentage points is invisible to the eye and irrelevant for most design work, but it can matter in automated pipelines that compare colors programmatically. If your token validation script checks whether an exported HEX value matches the source HSV definition, expect these small offsets and compare within a tolerance rather than requiring exact equality. Storing the original HSV coordinates alongside the derived HEX value in your token file lets you verify the conversion while still using HEX as the primary display and export format.
HSV to HEX for design token documentation and handoff
Design token documentation tools (Storybook, Zeroheight, Supernova, Backlight) expect colors in HEX format for display in color swatches. When your design tokens are defined in HSV (common when the design team works primarily in Photoshop), the HSV-to-HEX conversion is the bridge between the design tool's native format and the documentation tool's expected input.
The conversion pipeline for token documentation is: HSV → RGB → HEX. Each step is lossless for valid inputs (H: 0–360, S: 0–100, V: 0–100). The resulting HEX string is always six characters, lowercase, with a # prefix. Building on this, if your token pipeline uses Style Dictionary, add a custom transform that performs the HSV-to-HEX conversion. Style Dictionary's built-in transforms include color/hex and color/css, but not hsv/hex directly. A custom transform that accepts { h, s, v } token values and outputs a HEX string lets your designers work in HSV while your documentation shows HEX.
HSV to HEX for email HTML and SVG compatibility
Email HTML requires HEX colors because many email clients (Outlook, Gmail in certain modes) do not support rgb(), hsl(), or other CSS color functions. When your design team provides colors in HSV (from Photoshop or a color picker), converting to HEX is the required step before writing email inline styles, and you can get email-safe hex from a Photoshop color without leaving the browser. The conversion is the same as for any other use case: HSV → RGB → HEX.
SVG color attributes also expect HEX or rgb() values. When generating SVG icons or illustrations programmatically from HSV color data (for example, a chart library that lets users pick colors in a picker), convert to HEX before writing the SVG fill or stroke attribute. Building on this, inline SVG in HTML accepts the same color formats as CSS, but for maximum compatibility with older SVG viewers and export tools, HEX is the safest choice. The converter on this tool outputs HEX values that paste directly into SVG attributes: fill="#3b82f6".
HSV to HEX in game development and creative coding
Game engines and creative coding frameworks (p5.js, Processing, Unity) often use HSV for color manipulation because it maps intuitively to the way artists think about color. A game that shifts the hue of a character's aura over time does so by incrementing the HSV hue angle and converting to RGB for the rendering API. The HSV-to-HEX conversion is relevant when the game exports color values to a web-based UI or when the game's configuration files store colors as HEX strings.
In p5.js, the colorMode(HSB) function lets you work in HSV space directly, and the color() function returns a color object that the rendering engine converts to RGB internally.4 If you need the HEX value (for example, to send to a web API or write to a CSS file), call hex() on the color object, which returns the HEX string. Building on this, Unity's Color.HSVToRGB() function returns a Color object with float channels (0–1), which you then convert to 0–255 integers and then to HEX.5 The multi-step conversion is necessary because Unity does not provide a direct HSV-to-HEX function.
Use this when a color defined in a design tool's HSB panel (Photoshop, macOS Color Picker) needs to be expressed as a HEX string for a CSS stylesheet, a design token file, or a Figma fill field.
Photoshop brand color → CSS hex
hsv(74, 22%, 98%)
#f3fbc5
Paste directly into a CSS variable: --color-lime-light: #f3fbc5
Photoshop vivid accent → Figma fill
hsv(217, 76%, 96%)
#3b82f6
This is the Tailwind blue-500 value.
- 1.
"HSL and HSV," Wikipedia, en.wikipedia.org, accessed June 2026. https://en.wikipedia.org/wiki/HSL_and_HSV
- 2.
"Outlook doesn't understand specific rules of my inline code," Stack Overflow, stackoverflow.com, accessed June 2026. https://stackoverflow.com/questions/38832309/
- 3.
Mozilla Developer Network, "<hex-color> CSS type," developer.mozilla.org, accessed September 2026. https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/hex-color
- 4.
p5.js, "colorMode," p5js.org, accessed June 2026. https://p5js.org/reference/p5/colorMode/
- 5.
Unity Technologies, "Color.HSVToRGB," docs.unity3d.com, accessed June 2026. https://docs.unity3d.com/ScriptReference/Color.HSVToRGB.html
Yes. HSB (Hue, Saturation, Brightness) and HSV (Hue, Saturation, Value) are identical color models. Photoshop calls it HSB; most programming literature uses HSV. The coordinates are the same and no conversion is needed between the two names.
In Photoshop's Color Picker, H is the hue in degrees (0–360), S is saturation as a percentage (0–100%), and B is brightness (value) as a percentage (0–100%). Enter those three values into this converter to get the HEX equivalent.
The tool outputs lowercase HEX (#3b82f6). Both uppercase and lowercase are valid CSS. If your codebase uses a linter that enforces uppercase, paste the result and your linter will flag and fix it automatically.
The HSV model does not encode alpha. This converter produces 6-digit HEX for the RGB portion. To add alpha, append two hex digits after the six-character result: 80 for 50% opacity, ff for fully opaque.
No. CapyToolkit converts your HSV values to HEX entirely in your browser using JavaScript. Nothing you enter is uploaded or stored.
Color Code Converter
Every field in the converter is an input, so a HEX code from Figma, an RGB value from DevTools, an HSL token from a design system or an HSV triple from Photoshop fills all the remaining formats in the same pass. The guide below covers which format to choose for each job, round-trip precision, alpha handling, and color conversion inside CI and design token pipelines.
Color formats splinter the same visible color into incompatible representations.
A HEX code from Figma, an rgb() value from DevTools, an hsl() token from a design system, an HSV triple from Photoshop, and an oklch() coordinate from a Tailwind v4 config all describe the same thing, yet no single tool input accepts them all.1 Switching between formats by hand means parsing or computing channel values that become error-prone under time pressure, especially when alpha channels or shorthand notation are involved.
When format friction slows you down
Format friction appears at every design-to-code boundary. A designer sends #c8ff00 from Figma and the developer needs rgb() for a canvas call. A style guide token uses hsl() for readability while an email template requires the same value in HEX. A Photoshop HSB entry from a print team has to become an oklch() coordinate before it can land in a CSS Color Level 4 stylesheet. Color code conversion therefore recurs at every tool handoff rather than being a one-time setup step. A converter that handles all five formats in one interface removes the per-transition lookup and arithmetic. Giving every downstream consumer the format it expects keeps lint rules, design reviews, and handoff documents in sync without manual recalculation.
Which format to choose
HEX is the most portable format. It pastes cleanly into CSS, HTML, Figma, and Slack without breaking surrounding syntax. RGB is the native format for canvas APIs, WebGL uniforms, and most JavaScript color pickers. HSL is the best format for manual adjustment because you can hold hue and saturation constant while varying lightness to generate a shade scale. HSV is what Photoshop and macOS Color Picker use internally.2 OKLCH is the right format for building perceptually uniform color scales in CSS Color Level 4 or Tailwind v4. Furthermore, named CSS colors cover only 16 basic plus about 150 extended keywords, so use them when the name improves readability, but never as a general interchange format.3
Round-trip precision and rounding
Converting between formats is not always perfectly reversible. Each step through a floating-point intermediate accumulates rounding error. A HEX → OKLCH → HEX round-trip may shift one RGB channel by 1. A HEX → HSL → HEX round-trip may also shift by 1. These differences sit below the threshold of human perception because two colors differing by 1 in one channel out of 255 are visually indistinguishable on any consumer display. The only workflows where round-trip precision matters are those that compare colors programmatically, such as automated design token audits that diff every committed value against the source of truth before a release artifact is published.
Real-time multi-format editing workflows
A converter that updates all five formats simultaneously as you type lets you view all five color formats at once, which eliminates the mental overhead of tracking which format you are working in. When you paste a HEX value, the RGB, HSL, HSV, and OKLCH fields update instantly, giving you the coordinates you need for any downstream tool without a second conversion step. This is the workflow that design-to-code handoff tools need: a designer sends HEX, the developer copies the OKLCH value for their Tailwind v4 config, and the email developer copies the same HEX for the email template, all from the same screen.
Using the converter as a design token audit tool
Paste each token from your design system into the converter and compare the OKLCH coordinates across your palette. Tokens at the same shade level (for example, all your 500-level colors) should have similar L values if your palette is perceptually consistent. A blue-500 at L=0.61 and a red-500 at L=0.45 signals a lightness inconsistency that will look uneven in your UI. The converter gives you the diagnostic data to find and fix these mismatches before they reach production.
The audit also works in reverse: paste an existing palette from a competitor or a legacy brand guide and read its OKLCH coordinates to see where its lightness curve drifts. That external comparison is useful when you are harmonizing an acquired product line with your own tokens, because the numbers expose which shades were tuned by eye and which follow a real scale. Keeping the audit loop in the same tool where you convert means you can fix a value and re-check it in seconds rather than switching contexts.
Handling alpha channels across all five formats
Alpha channels are handled differently in each format, and the converter must track them separately. HEX uses an optional 8-digit form (#rrggbbaa), RGB uses rgba() with a fourth 0 to 1 value, HSL uses hsla() or the slash-separated Level 4 syntax, HSV has no standard alpha representation, and OKLCH uses the slash-separated alpha syntax.4 When you input a color with alpha, the converter propagates the alpha value to every format that supports it and drops it from HSV. For workflows that need alpha in every output, use rgba() or the Level 4 slash syntax as your interchange format, since they are the most widely supported alpha-capable formats.
Compositing and blending with alpha in different color spaces
Blending two semi-transparent colors produces different results depending on the color space. Compositing in sRGB (the default for most browsers) produces a darker result than compositing in linear light or OKLCH because the gamma curve distorts the midpoint. CSS Compositing and Blending Level 1 defines the mix-blend-mode property, which operates in sRGB by default and builds on the Porter Duff source-over model used by earlier SVG and CSS implementations.5 For perceptually accurate blending, convert both colors to OKLCH, perform the blend in that space, and convert back to sRGB for display. This is not yet possible in pure CSS but is straightforward in JavaScript for canvas-based rendering.
Color format conversion in CI and design token pipelines
Automated design token pipelines convert colors between formats at build time using tools like Style Dictionary, Theo, or Amazon Style Dictionary. A token defined as { "color": { "primary": { "value": "#3b82f6" } } } passes through transforms that output the same color in HEX, RGB, HSL, and OKLCH for different consumption targets. The pipeline emits a CSS file with oklch() values, a Swift file with UIColor values, and a JSON file with HEX strings, all derived from the same source. Building this pipeline once eliminates manual conversion errors across every platform your design system targets.
Validating token output with automated contrast checks
Add an automated contrast check to your CI pipeline that reads every foreground-background token pair from your generated CSS and verifies the WCAG ratio. Tools like pa11y, axe-core, or a custom script using the WCAG relative luminance formula can flag token pairs that fall below 4.5:1 before they ship. Running this check on every pull request catches accessibility regressions that manual review misses, especially when a designer updates a brand color and the ripple effect on contrast ratios is not immediately obvious.
Use this whenever you need to move a color between tools that use different native formats, such as converting Figma HEX for a canvas API call, mapping a CSS variable onto a Photoshop panel value, or turning an OKLCH design token into an email-safe HTML attribute.
Figma brand color → canvas API
#c8ff00 (from Figma HEX field)
rgb(200, 255, 0)
Type #c8ff00 into the HEX field; the RGB field updates instantly.
Photoshop HSB → CSS custom property
hsv(217, 76%, 96%)
oklch(0.612 0.212 261.5)
Enter HSV in the HSV field, then copy the OKLCH output for your CSS variable.
- 1.
MDN Web Docs, "<color> CSS type — Syntax," developer.mozilla.org, accessed June 2026. https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/color_value
- 2.
Adobe, "Choose colors with the Adobe Color Picker," helpx.adobe.com, accessed June 2026. https://helpx.adobe.com/photoshop/using/choosing-colors.html
- 3.
Mozilla Developer Network, "<named-color> CSS type," developer.mozilla.org, accessed September 2026. https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/named-color
- 4.
W3C, "CSS Color Module Level 4: Color," w3.org, accessed June 2026. https://www.w3.org/TR/css-color-4/
- 5.
World Wide Web Consortium, "Compositing and Blending Level 1," W3C Candidate Recommendation Draft, March 2024. https://www.w3.org/TR/compositing-1/
HEX (#rrggbb and shorthand #rgb), RGB (rgb(r, g, b) and space-separated), HSL (hsl(h, s%, l%)), HSV (hsv(h, s%, v%)), OKLCH (oklch(L C H)), and CSS named colors like "tomato" or "rebeccapurple". Type into any field and all others update instantly.
Every field accepts input. Click or tab into any field, type your value in its native format, and all other fields update. The HEX field and the canvas color picker are the most common starting points, but the converter works equally well from any format.
The conversion pipeline passes through floating-point intermediate values, and different tools round at different points. A difference of 1 in one RGB channel is within normal floating-point tolerance. If two tools produce values that differ by more than that, one is likely using an incorrect conversion formula.
Yes. All conversions run in your browser once the page loads. CapyToolkit does not require a network connection after the initial load, and nothing is sent to any server.
It shows the closest CSS named color to your current input, found by measuring perceptual distance in OKLab space rather than raw RGB distance. The small swatch next to the name shows what that named color looks like, so you can judge how close the approximation is before deciding whether to use it.
RGB, HSL, and HSV explained
RGB expresses the same channel values as HEX in decimal notation: rgb(255, 85, 0) describes the very same orange as #ff5500. Browsers treat RGB as their native color format, so it is the most direct way to specify a color in CSS without any conversion step. Each of the three numbers maps to the red, green, and blue intensity in that order, which makes the relationship between the channels and the final color easy to reason about when you are tweaking values by hand. Going the other way, decimal 59 becomes 3b because 59 is three sixteens plus eleven, and any value below 16 takes a leading zero so the pair stays two digits wide.
How HSL and HSV describe a color
HSL (hue, saturation, lightness) and HSV (hue, saturation, value) trade that channel-level precision for a layout that feels more intuitive when you are adjusting a color by eye. Hue is a zero-to-360 degree angle on the color wheel, where 0 and 360 both land on red, 120 lands on green, and 240 lands on blue.2 Saturation controls how vivid or grey the color appears. The third channel is where HSL and HSV diverge: in HSL a lightness of 100% gives white, while in HSV a value of 100% gives the brightest version of the hue itself.3 For adjusting brightness without washing a color out, HSV is often more predictable. The hue angle carries over unchanged between the two models, while HSV value is the largest channel value and HSV saturation is the chroma gap measured against it, which is why one color holds different coordinates in each model.
Convert HEX to RGB
Pasting a HEX code fills the RGB field with the decimal channels that
rgba(), canvas and WebGL code expect, so you never decode the
hexadecimal pairs by hand. The guide below walks through how each pair of
digits maps to a channel, shorthand codes and rounding, and why sRGB is the
only color space you can safely assume when a HEX code arrives without a color
profile.
Design tools export colors as HEX codes, but CSS functions like rgba() and linear-gradient() expect numeric RGB channels. Switching between them manually means decoding two hex digits per channel, and that decoding step is easy to get wrong under time pressure.
How HEX to RGB conversion works
HEX encodes each color channel as a two-digit base-16 number. Converting to RGB means translating each pair from hexadecimal to decimal: the first pair is the red channel, the second green, the third blue.1 Concretely, c8 in hex equals (12 × 16) + 8 = 200 in decimal, ff equals 255, and 00 equals 0. Because the encoding is purely positional, the conversion is exact for any standard six-digit HEX value, with no rounding or approximation.
Channel order is fixed
The six digits always map to red, green, and blue in that order. There is no header or metadata inside the string; the position alone determines the channel. This positional simplicity is what makes the conversion reliable across every programming language and browser implementation. Whether you decode the string in JavaScript, Python, or Rust, the result is identical because the format itself carries no ambiguity.
Because the channel order never changes, you can safely read just one channel from a HEX string without converting the rest. If you only need the red value, take characters 1 and 2 and convert that single pair, which is the same shortcut the CSS red() function uses internally. This fixed ordering is also why HEX survives as the default export from design tools: there is no header or flag to strip before the numeric conversion begins, so the decoding step stays simple and predictable.
Why base-16 maps cleanly to base-10
Each hex digit represents four binary bits, so two digits represent one full byte (8 bits). That is why hex pairs line up perfectly with 0–255 decimal values, and why the conversion is just a base conversion rather than a lookup or approximation. For example, the hex value 1a translates to (1 × 16) + 10 = 26 in decimal, with no rounding and no edge case to handle.
Where HEX to RGB conversion comes up
Design tools export nearly every color as HEX. Figma, Sketch, and Photoshop all default to #rrggbb in their copy-as-CSS outputs. Consequently, any workflow that starts in a design application and ends in code requires the RGB form at some point, whether that code is a canvas 2D context, a WebGL shader uniform, or a Node.js server rendering PNG images. Furthermore, JavaScript's CSS Object Model exposes computed colors as rgb() strings, making RGB the natural interchange format between design pipelines and browser code.
RGB as a common interchange format
When color data moves between tools, RGB is the lowest common denominator. Design applications, image processors, and browser APIs all understand the three-channel decimal form, even if they prefer HEX or HSL internally. Converting HEX to RGB early in the pipeline avoids repeated conversions downstream and keeps color values consistent across every stage of the build. If your team updates brand colors in a single source of truth, converting once to RGB and distributing that value everywhere is far safer than re-decoding HEX strings at every consumption point.
HEX to RGB edge cases and rounding
Shorthand HEX values like #f50 expand before conversion: each single digit doubles to a pair, yielding #ff5500.2 An optional seventh and eighth character encode alpha on the same 00–ff scale, so #ff550080 is orange at roughly 50% opacity, where 80 hex equals 128.3 Yet the rgb() function has no alpha slot, so use rgba() for any transparent variant.4
Floating-point channels need an extra step
Floating-point channel values in the 0.0–1.0 range appear frequently in WebGL, Three.js, and shader code. To convert a HEX color to that form, first decode the hex pairs to 0–255 integers as usual, then divide each integer by 255.0. For example, #c8ff00 becomes (0.784, 1.0, 0.0). This extra division is straightforward but easy to forget, especially when your pipeline mixes integer and float color representations. In GLSL, the normalized triplet is often declared as a vec3 uniform, so forgetting the division produces colors that are far brighter than intended.
When shorthand causes confusion
Three-digit HEX (#f50) looks similar to a function call or a CSS class name at a glance. If your source data mixes shorthand and six-digit values, normalize them all to six digits before conversion so downstream code does not accidentally treat them as different colors. This is especially important when pulling colors from minified stylesheets or legacy design files where shorthand is common. A color named #fff and a color named #ffffff are identical after normalization, but raw string comparison would treat them as distinct values.
Using RGB output in canvas and WebGL contexts
Canvas 2D contexts accept RGB colors as strings: ctx.fillStyle = "rgb(200, 255, 0)" works in every browser. Yet the canvas API also accepts hex strings, HSL, and even named colors, so the practical reason to convert a design color to rgb() for canvas is consistency with an existing codebase or a team style guide that mandates rgb() notation. Building on this, if your project uses TypeScript with strict typing for color values, having the explicit rgb() form makes it easier to validate color strings at build time.
WebGL shaders require colors as normalized float triplets in 0.0–1.0 space, not as 0–255 integers.5 After converting HEX to RGB, divide each channel by 255.0 to get the float triplet your shader expects. For example, rgb(200, 255, 0) becomes vec3(0.784, 1.0, 0.0) in GLSL. Some WebGL frameworks (Three.js, Babylon.js) accept 0–255 integers and normalize internally, but the raw WebGL API does not. Converting through RGB first gives you explicit control over the normalization step, which matters when you need precise color values for lighting calculations or color grading.
HEX to RGB in server-side and build-time workflows
Server-side rendering pipelines often need HEX-to-RGB conversion at build time rather than at runtime. Node.js packages like color-convert, tinycolor2, and culori all provide HEX-to-RGB functions that return arrays of integers. If your build process generates CSS custom properties from a design token file, the conversion from HEX tokens to RGB values happens once during the build, and the resulting CSS ships the rgb() values directly to the browser without any client-side conversion.
CSS preprocessors like Sass and Less also provide HEX-to-RGB functions: red($color), green($color), and blue($color) in Sass extract individual channels. These functions are useful when you need to construct rgba() values from a HEX base: rgba(#c8ff00, 0.5) in Sass compiles to rgba(200, 255, 0, 0.5) in CSS. Building on this, PostCSS plugins can perform the same transformation at build time, converting all HEX values in your stylesheet to rgb() notation if your project convention requires it.
Color space implications: sRGB is the only safe assumption
Every HEX code encodes sRGB values. There is no HEX syntax for P3, Adobe RGB, or any other color space.6 When you convert #c8ff00 to rgb(200, 255, 0), the result is an sRGB color. If you need the same visual color in P3 space, the numeric RGB values will be different, but HEX cannot express that difference. This is a fundamental limitation of the HEX format: it is sRGB-only by definition.
CSS Color Level 4 addresses this with the color() function: color(srgb 0.784 1.0 0.0) is the explicit sRGB equivalent of #c8ff00, while color(display-p3 0.85 0.95 0.12) is a P3 color that may look similar but has different numeric values.7 Building on this, when you convert HEX to RGB and use the result in CSS, you are implicitly working in sRGB. If your design system targets P3 displays, you need a separate P3 color definition; the HEX-to-RGB conversion alone cannot get you there.
Use this when you have a HEX color from a design file (Figma, Sketch, Photoshop) and need the rgb() or rgba() value for a CSS stylesheet or a canvas API call.
Figma brand color → CSS rgba with opacity
#c8ff00
rgb(200, 255, 0)
For rgba(), append the alpha: rgba(200, 255, 0, 0.5)
Shorthand HEX → full RGB
#f50
rgb(255, 85, 0)
- 1.
W3C, "A Standard Default Color Space for the Internet - sRGB," w3.org, November 1996. https://www.w3.org/Graphics/Color/sRGB.html
- 2.
MDN Web Docs, "<hex-color>," developer.mozilla.org, accessed June 2026. https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/hex-color
- 3.
W3C, "CSS Color Module Level 4: Color," w3.org, accessed June 2026. https://www.w3.org/TR/css-color-4/#color
- 4.
WebGL Fundamentals, "Shaders and GLSL," webglfundamentals.org, accessed June 2026. https://webglfundamentals.org/webgl/lessons/webgl-shaders-and-glsl.html
- 5.
CSS-Tricks, "Almanac: Functions — color()," css-tricks.com, accessed June 2026. https://css-tricks.com/almanac/functions/c/color/
- 6.
Chrome for Developers, "Access more colors," developer.chrome.google.cn, accessed June 2026. https://developer.chrome.google.cn/docs/css-ui/access-colors-spaces
- 7.
IEC, "Multimedia systems and equipment — Colour measurement and management — Part 2-1: Colour management — Default RGB colour space — sRGB," IEC 61966-2-1, 1999. https://webstore.iec.ch/en/publication/6169
A HEX color is three pairs of base-16 digits. The first pair is the red channel (00–ff), the second is green, the third is blue. #c8ff00 means red = c8 (200), green = ff (255), blue = 00 (0).
Use rgba() instead of rgb() and add a fourth value from 0 (transparent) to 1 (opaque). rgb(200, 255, 0) at 50% opacity becomes rgba(200, 255, 0, 0.5).
Yes. The tool expands each digit to a pair: #f50 becomes #ff5500, which is rgb(255, 85, 0).
No. Every HEX-to-RGB conversion this tool performs runs entirely in your browser, and no color value you type is ever transmitted to a server or logged anywhere.
Yes. Shorthand HEX values expand before conversion: #fff becomes #ffffff, which is rgb(255, 255, 255). CapyToolkit handles both three-digit and six-digit forms, so you can paste color codes from minified CSS or design tokens without pre-processing them.
Convert HSL to RGB
Canvas contexts, WebGL shaders and server-side image libraries ask for numeric
red, green and blue channels, so an hsl() value has to be
decomposed before you can use it there. Typing it into the HSL field fills RGB
immediately, and the guide below explains the conversion steps, hue values
above 360 and why two conversion paths can land one unit apart.
Most rendering pipelines expect RGB, not HSL.
When a canvas context, a WebGL shader, or a server-side image library asks for numeric color channels, you need to decompose your hsl() values into the red, green, and blue integers those APIs understand. The conversion is deterministic and lossless for standard HSL inputs: any well-formed hsl() value maps to exactly one rgb() triple, with no ambiguity about which color it represents across platforms.
How HSL to RGB conversion works
Inside the HSL model, hue is a 0–360 degree angle, saturation a 0–1 ratio, and lightness a 0–1 ratio. The conversion derives three intermediate chroma values from saturation and lightness, then maps each onto the correct sextant of the hue wheel (such as the 0–60° and 60–120° ranges) to produce the red, green, and blue channels.1 Consequently, hues at sextant boundaries (0°, 60°, 120°, 180°, 240°, 300°) produce cleaner integer RGB values, while intermediate hues accumulate sub-integer remainders that the final Math.round() step resolves.
Why the sextant model matters
Each 60-degree sector of the hue wheel assigns a different channel as the maximum and a different formula for the remaining two channels. The red channel dominates the first sector (0° to 60°), green dominates the second (60° to 120°), and blue takes the third. This rotating assignment repeats for the second half of the wheel. Understanding which sector your hue falls in tells you which RGB channel will be the largest after conversion, which helps when debugging unexpected color shifts.
The sextant logic also explains why neighboring hues shift only one channel at a time. In the first sector red peaks while blue holds at zero, so a small hue change moves mostly between red and green as you cross into the next sector. That behavior is why converting a hue near a boundary can change two channels instead of one, and why designers sometimes nudge a hue back inside a sector to keep a single-channel gradient.
Where HSL to RGB conversion comes up
Three workflows drive most HSL-to-RGB conversions. Design systems that define palette tokens as hsl() variables need RGB output to export values to platforms that only accept hex or numeric channels. WebGL fragment shaders require float triplets in 0–1 space, which means dividing each 0–255 RGB channel by 255 after conversion. Furthermore, server-side renderers differ in the color syntax they parse out of the box: ImageMagick accepts hsl() triples directly alongside rgb() and hex,2 but most Node.js image pipelines and Cairo-based SVG exporters expect numeric channels or hex strings, making the conversion a required step before any server-side image operation.
Server-side rendering constraints
Any environment that processes images outside the browser typically lacks native HSL support. Node.js canvas implementations, Rust image crates, and Python imaging libraries all expect colors in RGB or hex format. When your design tokens live in HSL because they were authored for a CSS-in-JS system, you must convert them before the server-side code can use them. This is especially common in static site generators that produce social media preview images at build time.
HSL to RGB edge cases and rounding
Achromatic inputs (saturation 0) produce equal red, green, and blue channels regardless of the hue angle, which becomes irrelevant and is ignored. Hue values outside 0–360 wrap modulo 360: 390° and 30° produce identical output.1 Saturation or lightness above 1.0 are undefined; clamp them before conversion. Because RGB requires integer channels and the conversion intermediate is floating-point, each channel rounds at the final step. Yet rounding means a round-trip of HSL → RGB → HSL may shift the hue or saturation by a fraction of a percent, which is perceptually invisible but measurable in exact comparisons.
When achromatic output catches you off guard
If you convert an HSL color with saturation near zero, the hue angle has almost no effect on the RGB output. This can produce unexpected results when you expect a warm grey (based on a hue near 30°) but get a neutral grey because the saturation value was 0.1% instead of 1%. Always verify the saturation value before relying on hue to influence the output in low-saturation regions of the HSL space.
HSL to RGB for server-side image generation
Server-side image generation tools (Node.js sharp, Python Pillow, ImageMagick) accept RGB values but not HSL, so you need to feed an hsl() color to a server-side renderer in the format it accepts. When your design system stores colors as HSL tokens and your server-side code needs to generate images (social media cards, email headers, PDF covers), you must convert HSL to RGB before passing the values to the image library. The conversion is the same algorithm as the client-side version, but the implementation details differ across languages.
In Python, the colorsys module provides hls_to_rgb() (note: HLS, not HSL, with the L and S channels in a different order).3 In Node.js, packages like color-convert provide hsl.rgb(h, s, l) which returns [r, g, b] as 0–255 integers.4 Building on this, always verify the channel order and range expected by your specific library. Some libraries expect 0–1 floats, others expect 0–255 integers, and a few use 0–100 percentages. Passing the wrong range produces silently wrong colors that are hard to debug because the code runs without errors.
HSL to RGB in WebGL shader uniforms
WebGL shaders require colors as vec3 or vec4 float triplets/quadruplets in 0.0-1.0 space.5 Converting HSL to RGB for a WebGL uniform is a two-step process: first convert HSL to 0–255 RGB integers, then divide each by 255.0 to get the float triplet. Some developers implement the HSL-to-RGB conversion directly in GLSL to avoid the CPU-side conversion, but the GLSL implementation is more complex and slower than doing the conversion once on the CPU and passing the result as a uniform.
The GLSL implementation requires replicating the hue-sextant logic (six 60-degree sectors with different channel assignments) using step() and mix() functions. This is useful when you need to convert HSL to RGB per-fragment for a color picker visualization, but for static colors, the CPU-side conversion is simpler and faster. Building on this, if your application dynamically adjusts HSL values (for example, a color picker UI), do the conversion in JavaScript on the CPU and update the uniform, rather than implementing the conversion in the shader.
Precision considerations for HSL-to-RGB in design systems
Design systems that store colors as HSL and convert to RGB at build time need to decide how many decimal places to preserve in the HSL coordinates. Storing hue as an integer (217) and saturation/lightness as integers (91%, 60%) is sufficient for most use cases. Storing additional decimal places (217.3, 91.2%, 59.8%) provides marginally better precision but increases token file size and provides no visible benefit for 8-bit display output.
The practical limit is the 0–255 integer RGB output: any HSL precision beyond what affects the rounded RGB value is wasted. For a hue angle, this means roughly one decimal place is the useful maximum. For saturation and lightness percentages, one decimal place is also sufficient. Building on this, if your design system uses OKLCH as the canonical format and converts to HSL as an intermediate step, the additional conversion step may introduce rounding that would not exist if you converted directly from OKLCH to RGB. Minimize conversion steps in your token pipeline to preserve precision.
Use this when a design token or CSS variable defined in HSL needs to be passed to a canvas API, a WebGL shader, or a server-side renderer that only accepts numeric RGB channels.
HSL design token → canvas fillStyle
hsl(74, 100%, 50%)
rgb(200, 255, 0)
Canvas accepts the string directly: ctx.fillStyle = "rgb(200, 255, 0)"
HSL shade variant → WebGL float triplet
hsl(217, 91%, 30%)
rgb(6, 71, 153)
Divide by 255 for WebGL: vec3(0.024, 0.278, 0.600)
- 1.
"HSL and HSV," Wikipedia, en.wikipedia.org, accessed June 2026. https://en.wikipedia.org/wiki/HSL_and_HSV
- 2.
ImageMagick, "Color Names," imagemagick.org, accessed August 2026. https://imagemagick.org/color/
- 3.
"colorsys," Python, docs.python.org, accessed June 2026. https://docs.python.org/3/library/colorsys.html
- 4.
Heather Arthur and Josh Junon, "color-convert," github.com, accessed August 2026. https://github.com/Qix-/color-convert
- 5.
"GLSL shaders," MDN Web Docs, developer.mozilla.org, accessed June 2026. https://developer.mozilla.org/en-US/docs/Games/Techniques/3D_on_the_web/GLSL_Shaders
Converting HSL to RGB then back to HSL may shift saturation or hue by a fraction of a percent due to integer rounding in the RGB channels. The visual difference is imperceptible, but design tools that store colors as exact decimal values may show a tiny drift. Keep the authoritative copy in HSL if you defined the color there.
The conversion wraps hue modulo 360. A hue of 390° produces the same output as 30°. Negative hues wrap the same way: -10° becomes 350°. This matches how CSS hsl() handles out-of-range hue angles.
Pass the three integers as a string to fillStyle: ctx.fillStyle = "rgb(200, 255, 0)". For transparency, use rgba() with a fourth value from 0 to 1. Canvas also accepts hex strings if you convert the RGB integers to hex pairs after conversion.
Yes. CapyToolkit accepts hsl(74, 100%, 50%) with percent suffixes as well as the unitless form hsl(74, 1, 0.5) used by some libraries. All conversions run locally in your browser; nothing is uploaded to any server.
Each path accumulates floating-point rounding at different points in the calculation. HSL → RGB and HEX → HSL → RGB pass through different intermediate precisions before the final Math.round(). A difference of 1 in one channel is within the expected rounding tolerance and is perceptually invisible.
Convert HSV to RGB
HSV describes a color the way you pick it on a color wheel, by hue, the amount
of gray and the amount of black, while RGB describes the light a screen emits.
Entering HSV fills the RGB field with integer channels ready for
rgb(), and the guide below covers the formula, real-time canvas
work, data visualization palettes and moving Photoshop HSB values into CSS.
HSV describes color the way artists mix paint.
Hue names the color family, saturation controls how much grey dilutes the pure hue, and value determines how much black reduces the brightness. Converting HSV to RGB is necessary whenever a color defined by a design tool, a color picker widget, or an image processing API needs to be expressed as the numeric red, green, and blue channels that CSS, canvas, and most rendering engines actually consume.
How HSV to RGB conversion works
The HSV-to-RGB algorithm divides the hue into six equal sectors of 60 degrees each. Within each sector, three intermediate values (P, Q, and T) are computed from value and saturation using different linear combinations. Depending on which sector the hue falls in, the algorithm assigns P, Q, and T to the red, green, and blue channels in a different order.1 Consequently, converting hues at the boundary of two sectors (60°, 120°, 180°, 240°, 300°) produces the purest integer RGB values, while intermediate hues carry floating-point remainders that round to the nearest integer.
Why sector boundaries produce cleaner integers
At a sector boundary, the hue aligns exactly with one of the primary or secondary color positions on the wheel. For example, a hue of 120° places green at full value with red and blue both at zero, producing the clean integer rgb(0, 255, 0). As the hue moves away from the boundary, the channel assignment shifts gradually between sectors, introducing fractional values that cannot be represented exactly as 0–255 integers and must be rounded.
The P, Q, and T intermediates are what make the sector math tractable. Once the sector index is known, they give the high, low, and blended channel values in a fixed pattern, so the only work left is assigning them to red, green, or blue in the order the sector demands. That is also why the rounding happens at the very end: the intermediate arithmetic stays in floating point until every channel is decided, so rounding error does not compound across steps.
Where HSV to RGB conversion comes up
Photoshop, Sketch, and most native OS color pickers expose color in HSB/HSV. A developer who reads a color from Photoshop's HSB panel and needs it in CSS or a canvas context must convert to RGB. Furthermore, color picker libraries like react-colorful, pickr, and vanilla-picker return HSV internally and may require RGB output for downstream use.2 Building on this, OpenCV image processing pipelines often work in HSV space and emit HSV values that need conversion to RGB before being written back to a display buffer.
From Photoshop to CSS in one step
When a designer sends you HSB values from Photoshop, the conversion path is straightforward: treat the HSB triple as HSV (the models are identical), convert to RGB using the standard algorithm, and format the result as a CSS rgb() string. The only common pitfall is confusing Photoshop's B (brightness/value) with HSL lightness, which produces a completely different color. Always verify by cross-checking: a Photoshop HSB of (217, 76, 96) converts to rgb(61, 153, 245), while an HSL lightness of 96% would produce a near-white result.
HSV to RGB edge cases and rounding
Value 0 produces black (0, 0, 0) regardless of hue and saturation: the hue and saturation become irrelevant when there is no light. Saturation 0 produces a grey with all three channels equal to the value: hsv(0, 0%, 50%) becomes rgb(128, 128, 128). Hue values outside 0–360 wrap modulo 360 before sector assignment.1 Yet because the final step rounds each channel to the nearest integer, a round-trip of HSV → RGB → HSV may return saturation or value shifted by up to 0.1 percentage points from the original.
Why value 0 overrides everything
When the value channel is zero, the mathematical effect is that every output channel multiplies by zero, regardless of what hue and saturation specify. The hue becomes a pointer into a color space that has no brightness, and saturation measures a difference that rounds to zero. This is why most HSV implementations treat value 0 as a special case that always returns black without running the sector computation, which also makes the conversion slightly faster for dark pixels in image processing loops.
HSV to RGB for real-time color manipulation in canvas
Canvas applications that let users adjust colors in HSV space (common in drawing apps, data visualization tools, and game engines) need fast HSV-to-RGB conversion on every frame, because fillStyle only accepts CSS color strings and not HSV coordinates.3 The standard algorithm with six hue sectors and conditional branching is fast enough for most use cases, but if you are converting millions of pixels per frame (for example, applying a hue shift filter to a full-screen image), the branching becomes a performance bottleneck.
A branchless implementation uses the same math but replaces the sector conditionals with arithmetic: compute a sector index with floor(hue / 60), then use modular arithmetic to assign the intermediate values to the correct channels. This runs faster on modern CPUs because it avoids branch misprediction penalties. Building on this, for GPU-based pixel manipulation, implement the HSV-to-RGB conversion as a fragment shader. The GPU's parallel architecture handles the per-pixel conversion much faster than a JavaScript loop, and the shader code is straightforward: compute the sector, calculate P/Q/T values, and assign to R/G/B based on the sector index.
HSV to RGB conversion in data visualization palettes
Data visualization libraries (D3.js, Chart.js, Observable Plot) often generate color palettes in HSV or HSL space because it is easy to create perceptually distinct hues by stepping the hue angle at equal intervals. For a 12-category palette, step hue by 30° (360 / 12) at fixed saturation and value. Converting each HSV step to RGB gives you the CSS color values for your chart series.
The problem with this approach is that equal hue steps do not produce equally perceived differences. The green region of the hue wheel (around 120°) looks more similar across small hue changes than the blue region (around 240°). For better perceptual uniformity, generate your palette in OKLCH space (equal hue steps in OKLCH produce more perceptually uniform results, because its L axis is perceived lightness rather than a comparison against other colors) and convert to RGB for CSS output.4 Building on this, D3.js provides d3.interpolateRainbow and d3.interpolateSinebow which use perceptually optimized hue trajectories rather than linear HSV hue stepping, producing more distinguishable colors for categorical data.
Photoshop HSB to CSS rgb(): a practical conversion workflow
When a designer provides Photoshop HSB values for a web project, translate a Photoshop HSB color to CSS rgb() by treating the HSB values as HSV, converting to RGB with the standard algorithm, and formatting as rgb(r, g, b). Photoshop's H range is 0–360, S range is 0–100, and B range is 0–100, which matches the standard HSV convention.5 No range scaling is needed (unlike OpenCV, which uses 0–180 for hue).
A common mistake is confusing Photoshop's B (brightness/value) with HSL lightness. Photoshop B of 100% at S 100% gives the most vivid version of the hue. HSL lightness of 100% always gives white. When converting Photoshop HSB to CSS, use the HSV-to-RGB algorithm, not the HSL-to-RGB algorithm. Building on this, if the designer also provides HSL values (from a different tool), do not mix the two: convert each to RGB independently and compare the results. If the RGB values differ, the source colors are different, and you need to clarify with the designer which one is correct.
Use this when you have a color from Photoshop, a JavaScript color picker, or an OpenCV pipeline expressed in HSV (or HSB) and need the rgb() triple for CSS or a browser rendering API.
Photoshop HSB → CSS rgb()
hsv(74, 100%, 100%)
rgb(200, 255, 0)
Photoshop labels these fields H, S, B, which is identical to HSV.
Color picker HSV → canvas fillStyle
hsv(0, 80%, 90%)
rgb(230, 46, 46)
Pass the string directly: ctx.fillStyle = "rgb(230, 46, 46)"
- 1.
"HSL and HSV," Wikipedia, en.wikipedia.org, accessed June 2026. https://en.wikipedia.org/wiki/HSL_and_HSV
- 2.
omgovich, "react-colorful/src/hooks/useColorManipulation.ts," github.com, accessed June 2026. https://github.com/omgovich/react-colorful/blob/master/src/hooks/useColorManipulation.ts
- 3.
Mozilla Developer Network, "CanvasRenderingContext2D: fillStyle property," developer.mozilla.org, accessed September 2026. https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/fillStyle
- 4.
Mozilla Developer Network, "oklch() CSS function," developer.mozilla.org, accessed September 2026. https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/color_value/oklch
- 5.
Adobe, "Set foreground and background colors in Adobe Photoshop," helpx.adobe.com, accessed June 2026. https://helpx.adobe.com/photoshop/desktop/adjust-color/choose-colors/set-foreground-and-background-colors.html
Yes. HSB stands for Hue, Saturation, Brightness, which is a different label for the same model as HSV (Hue, Saturation, Value). Photoshop uses HSB; most programming APIs and color science literature use HSV. No conversion is needed between the two labels.
Value 100% gives the brightest possible version of the hue at that saturation, but saturation also matters. At saturation 0% and value 100%, the result is white (rgb(255, 255, 255)) because zero saturation means no hue, only brightness.
Use the RGB to HEX converter on this tool. Enter the rgb() values into the RGB fields and the HEX field updates instantly. Alternatively, multiply each channel by 1, convert to two-digit hex, and concatenate with a # prefix.
The HSV model does not encode alpha. After converting to RGB, add an alpha channel by switching from rgb() to rgba() and appending a fourth value from 0 (fully transparent) to 1 (fully opaque). The converter handles the RGB portion; alpha is a separate concern.
No. CapyToolkit runs all color conversions locally in your browser using JavaScript. Nothing you enter is transmitted to any server.
Convert HEX to HSV
Photoshop, Procreate and many native color pickers take Hue, Saturation and
Value rather than a HEX code, so a brand color handed over as
#rrggbb usually has to be translated before you can type it into
them. The HSV field shows that translation as soon as you paste the HEX code,
and the guide below covers the formula, the HSB naming and the different value
ranges OpenCV uses.
Design files store colors as HEX. Photoshop and many color pickers use HSV.
When a developer receives a brand color as #rrggbb and needs to enter it into a tool that accepts only Hue, Saturation, and Value (or Brightness) fields, converting is the only path. Furthermore, image processing libraries like OpenCV, PIL, and ImageMagick offer HSV-space operations (adjusting hue, boosting saturation, normalizing brightness) that require the input color to be expressed in HSV coordinates rather than the hex string from the design handoff.
How HEX to HSV conversion works
Converting HEX to HSV routes through an intermediate RGB step. Each two-character hex pair decodes to a 0–255 integer, which then normalizes to a 0–1 float. The normalized triplet feeds into the HSV extraction: value is the maximum of the three channels, saturation is (max − min) / max when max > 0 and 0 otherwise, and hue maps the maximum channel to its position on the 0–360 degree color wheel using the other two channels as offsets.1
Consequently, a pure-primary color like #ff0000 yields a clean hsv(0, 100%, 100%) with no rounding involved. Pure primary colors convert cleanly because one channel reaches maximum (1.0 after normalization) while the other two are zero, which means the saturation denominator is exact and the hue formula simplifies to a whole-number degree. Secondary pure colors like #00ff00 and #0000ff behave the same way, each producing a hue angle that is a multiple of 120 degrees with no fractional remainder.
Where HEX to HSV conversion comes up
Three common workflows require HEX-to-HSV conversion. Photoshop's HSB color picker lets designers adjust brightness and saturation independently; entering the HSV values from a HEX brand color lets you fine-tune it without starting from scratch. OpenCV image processing pipelines threshold or adjust colors in HSV space, requiring the target color to be expressed as a triplet before constructing the range mask. Furthermore, color picker initialization in JavaScript components (react-colorful, Spectrum, pickr) often accepts an HSV or HSB object as its initialValue, while brand colors are almost always stored as HEX.
Brand guidelines almost universally specify colors as HEX codes because HEX is the most portable format: it works in CSS, HTML, email templates, design tools, and Slack messages without any reformatting. However, the tools that designers use to manipulate those colors operate in HSV, which is why converting from HEX to HSV is the first step whenever a brand color needs to be adjusted rather than simply applied as-is.
HEX to HSV edge cases and rounding
The HEX string #000000 (black) produces hsv(0, 0%, 0%): both saturation and value are zero, and hue is undefined, defaulting to 0° by convention. The string #ffffff (white) produces hsv(0, 0%, 100%): maximum value but zero saturation. Pure grey values have zero saturation at varying value levels.1 Yet because the conversion normalizes through floating-point arithmetic, values very close to 0% or 100% may display as 99.6% or 0.4% before rounding; the tool rounds to two decimal places for display.
When converting very dark or very light colors where the channel spread is small (for example, #0f0f10 or #f0f0f1), the saturation may appear as 0.4% or 0.2% where you might expect 0%. This is not a bug but a consequence of the normalized RGB values being slightly different from each other. In practice, you should treat saturation values below 1% as effectively zero when making design decisions.
Using HSV values in Photoshop and native color pickers
Photoshop's HSB panel is the most common destination for HSV values converted from HEX brand colors, and converting the hex first lets you enter a brand color into Photoshop's HSB panel directly. The panel accepts H as an integer 0 to 360, S as an integer 0 to 100, and B (brightness, identical to V) as an integer 0 to 100. After converting #3b82f6 to hsv(217, 76%, 96%), enter H: 217, S: 76, B: 96 directly into the Photoshop Color Picker.2 The color you see on screen should match the browser rendering of #3b82f6, assuming your display is calibrated to sRGB.
macOS Color Picker and system-level HSV input
macOS provides a system-wide color picker (accessible via any app's color panel or with the Digital Color Meter utility). Its color wheel interface operates in HSV: the wheel position sets hue and saturation, while a separate slider controls brightness. Converting a HEX brand color to HSV gives you the coordinates to enter directly. The Digital Color Meter can also read colors from the screen and display them in the color space of your choice, which is useful when you need to capture a color from a reference image and convert it to HEX or OKLCH for your stylesheet.3
The picker remembers the last mode you used, so if you leave it on the wheel, the next color you sample will already be in HSV and ready to reuse. That small convenience is why many designers keep the macOS picker open alongside their editor: they can sample a color from a screenshot, read its HSV coordinates, and paste them into a tool like Photoshop without switching applications. The same HSV coordinates also feed directly into the JavaScript color pickers described earlier, closing the loop between system, design, and code.
HSV in OpenCV and image processing pipelines
OpenCV uses HSV as its primary color space for thresholding and color detection. When you need to isolate a specific color range in an image (for example, detecting all blue UI elements in a screenshot), you define lower and upper HSV bounds and call cv2.inRange(). Converting your HEX brand color to HSV gives the center point for those bounds. A typical tolerance of ±10° in hue and ±20% in saturation and value captures natural color variation from anti-aliasing and compression artifacts.4
Why HSV works better than RGB for color thresholding
RGB thresholding requires you to define a cube in three-dimensional channel space, which is awkward when the color variation you want to capture is primarily a hue shift. HSV wraps the hue dimension into a single channel, so a hue tolerance becomes a simple numeric range rather than a complex multi-channel condition. Converting from HEX to HSV before constructing an OpenCV mask simplifies the threshold logic and produces more intuitive bounds that you can tune by adjusting a single hue range rather than three independent channel ranges.
Initializing JavaScript color pickers with HSV values
Most JavaScript color picker libraries store their internal state in HSV because the hue-saturation wheel plus brightness slider maps cleanly to the HSV cylinder. When you initialize a picker with a HEX or RGB value, the library converts to HSV internally to position the gradient thumb. Setting the initial value directly in HSV skips that conversion step and ensures the picker starts at exactly the coordinates you specify.
react-colorful, vanilla-picker, and pickr initialization
react-colorful accepts an HSV object as its color prop: <HexColorPicker color={{ h: 217, s: 76, v: 96 }} />. Vanilla-picker accepts an HSV string in its constructor: new VanillaPicker({ color: "hsv(217, 76%, 96%)" }). Pickr uses a setColor method that accepts HSV arrays: pickr.setColor([217, 76, 100]).5 In each case, converting your HEX to HSV first gives you precise control over the initial picker position, which matters when you are building a tool that needs to restore a previously saved color exactly.
Use this when a brand color from a style guide or design handoff in HEX needs to be entered into a Photoshop HSB panel, an OpenCV mask range, or a JavaScript color picker that accepts HSV as its input format.
Brand HEX → Photoshop HSB fields
#c8ff00
hsv(74, 100%, 100%)
Enter H=74, S=100, B=100 in the Photoshop Color Picker.
UI primary HEX → OpenCV color range
#3b82f6
hsv(217, 76%, 96%)
Use as the center point for a ±10° hue mask in OpenCV.
- 1.
"HSL and HSV," Wikipedia, en.wikipedia.org, accessed June 2026. https://en.wikipedia.org/wiki/HSL_and_HSV
- 2.
Adobe, "Choose colors with Adobe Color Picker," helpx.adobe.com, February 2026. https://helpx.adobe.com/photoshop/desktop/adjust-color/choose-colors/choose-colors-with-the-adobe-color-picker.html
- 3.
Apple, "Digital Color Meter User Guide for Mac," support.apple.com, accessed September 2026. https://support.apple.com/guide/digital-color-meter/welcome/mac
- 4.
omgovich, "react-colorful/src/hooks/useColorManipulation.ts," github.com, accessed June 2026. https://github.com/omgovich/react-colorful/blob/master/src/hooks/useColorManipulation.ts
- 5.
OpenCV, "Changing Colorspaces," docs.opencv.org, accessed June 2026. https://docs.opencv.org/4.x/df/d9d/tutorial_py_colorspaces.html
Photoshop uses HSB (Hue, Saturation, Brightness) as a label, but Brightness is the same channel as Value in HSV. The models are identical. Enter the HSV coordinates from this converter directly into Photoshop's H, S, and B fields.
No. The hue angle is derived solely from the relative position of the RGB channels, which are embedded in HEX. The conversion preserves hue exactly; only saturation and value are computed from the channel ratios.
Saturation 0% means the color is achromatic: a shade of grey with no hue component. The value channel determines how bright the grey is. Any HEX code with all three channel pairs equal (like #808080 or #cccccc) produces saturation 0%.
No. CSS does not define an hsv() function. To use these coordinates in CSS, convert them to HSL (the hue angle is the same) or to HEX/RGB using the other converters on this tool.
No. CapyToolkit converts your HEX to HSV coordinates entirely in your browser using JavaScript. Nothing you enter is sent to any server.
What makes OKLCH different
OKLCH stands for Lightness, Chroma, and Hue in the OKLab color space, and its defining property is perceptual uniformity. Equal numeric steps in any direction produce roughly equal perceived color differences, which is something HSL cannot guarantee.4 Two colors that share an identical HSL lightness value can look dramatically different in actual brightness to the human eye, because HSL lightness is computed from raw channel averages rather than from how people actually see luminance.
In practice, OKLCH is a reliable format for building color scales where every step should feel equally spaced from its neighbors. Modern browsers support it natively, so you can drop it straight into your CSS without any preprocessor or polyfill: color: oklch(0.65 0.18 30).5 That native support means the values you read in the converter are the same values the browser renders, which removes an entire class of surprises when a design moves from a mockup into production code.
NOTE OKLCH values may shift very slightly after a round-trip conversion through another format. The pipeline passes through floating-point intermediates and rounds back to integer zero-to-255 RGB at the end of the chain. The resulting difference is well below the threshold of human perception, so it will never be visible in a rendered interface.
CSS Color Converter for Developers
CSS accepts HEX, rgb(), hsl() and
oklch() for the same color, and the converter shows all of them
side by side so you can copy whichever syntax a stylesheet needs. The guide
below covers which syntax suits each CSS use case, alpha channels in the
modern color functions, relative color syntax, OKLCH against HSL, and
converting at build time or at runtime.
CSS supports five distinct color syntaxes in active use.
Legacy stylesheets use HEX and rgb() almost exclusively. Modern design systems add hsl() for maintainable tokens. CSS Color Level 4 introduces oklch() as the perceptually uniform format recommended for new color scales.1 Moving a color value between these syntaxes is a daily task for any developer who works across tools with different defaults, and the math behind OKLCH conversion is complex enough that doing it manually is impractical.
CSS color formats and their use cases
HEX is the most portable CSS color format, and every browser, tool, and email client that processes CSS accepts it. RGB is the format browsers use internally for computed styles and the one returned by DevTools, canvas APIs, and JavaScript getComputedStyle(). HSL is designed for human adjustment because you can hold the hue angle fixed while varying lightness to generate shade ramps. OKLCH is the CSS Color Level 4 format with perceptual uniformity, meaning equal numeric steps produce roughly equal perceived differences and making it the best choice for building accessible color scales. Furthermore, oklch() is now supported natively in Chrome, Firefox, Safari, and Edge without polyfills.2
Converting for specific CSS use cases
Inline SVG color attributes accept HEX or rgb() but oklch() is not yet reliably parsed by SVG viewers outside modern browsers. CSS custom properties accept any valid color value, including oklch(). CSS color-mix() and relative color syntax take an explicit interpolation color space, defaulting to oklab with shorter hue interpolation, which makes OKLCH or HSL the better choices for dynamic mixing.3 The output format choice therefore depends on where the value will be used, so you can pick the CSS color syntax your target accepts instead of defaulting to readability. Storing the canonical value in OKLCH and converting to HEX for compatibility is a sound pattern for modern CSS design systems, especially when a token pipeline can emit both formats from a single source definition.
Alpha channels and modern CSS color functions
Alpha is handled differently across CSS color formats. HEX supports it through an optional 8-digit form (#rrggbbaa), RGB uses rgba() with a fourth 0–1 value, and CSS Color Level 4 introduces a slash-separated alpha syntax for HSL, OKLCH, and the newer rgb() variant.4 The slash form looks like hsl(217 91% 60% / 0.5) or oklch(0.612 0.212 261.5 / 0.5). The legacy comma syntax (rgba(r, g, b, a)) is still required for some CSS 2.1 contexts, so you often need both forms in production. Building on this, CSS custom properties that define alpha-enabled tokens should use the Level 4 slash syntax to stay compatible with color-mix() and future color functions.
CSS Color Level 4 relative color syntax in practice
CSS Color Level 4 relative color syntax derives a new color from an existing one by specifying which channels to modify. The expression color(from var(--color-brand) oklch calc(l * 0.85) c h) produces a darker variant by reducing lightness to 85% of the original while keeping chroma and hue identical. This syntax works in any rule that accepts a color value, including background, border, box-shadow, and gradient color stops. All modern browsers support it as of 2023.
Chaining relative color operations
Chaining lets you derive an entire shade and tint family from a single base token by composing multiple relative color expressions in the same stylesheet. Starting from --color-primary: oklch(0.612 0.212 261.5), define --color-primary-light as color(from var(--color-primary) oklch calc(l + 0.18) calc(c * 0.8) h) and --color-primary-dark as color(from var(--color-primary) oklch calc(l - 0.18) calc(c * 0.9) h). Each derived value references the base token through var(), so changing --color-primary updates all variants automatically. This replaces the preprocessor loops or manual calculations that design token systems previously needed to generate shade scales.
Chaining also keeps the family coherent when the base changes, because every derived shade is computed from the live token rather than from a snapshot value. If a designer retunes the brand hue, the light and dark variants follow automatically instead of needing a separate pass through a conversion tool. That live dependency is the main reason to build shade families this way: the spreadsheet of hand-computed triples it replaces was always one edit behind the base color.
When to use OKLCH versus HSL in CSS today
HSL remains the better choice when you need to support browsers older than 2023, when your team is not familiar with perceptual color models, or when you are writing one-off CSS that does not go through a design token pipeline. OKLCH is the better choice for new design systems, for any project targeting modern browsers, and for workflows that require perceptual consistency across hue families. Both formats are valid CSS; the choice depends on your browser support requirements and whether perceptual uniformity matters for your use case.
Mixing OKLCH and HSL in the same stylesheet
You can use OKLCH for design tokens and HSL for one-off values in the same stylesheet without conflict. CSS does not require all colors to be in the same format. A practical pattern defines all semantic tokens in OKLCH (--color-primary: oklch(0.612 0.212 261.5)) and allows HSL for quick prototyping or third-party component overrides. The only place format consistency matters is inside color-mix() or relative color syntax, which require both operands to be in the same color space or to specify the target space explicitly.
Converting colors at build time versus runtime
Converting HEX to OKLCH at build time (via PostCSS or a design token compiler) produces static oklch() values in the output CSS, with no runtime conversion cost. Converting at runtime (via JavaScript in the browser) is necessary when the input color comes from user interaction, a theme editor, or an API response. For most design systems, build-time conversion is the right choice: it emits plain CSS, works without JavaScript, and adds zero runtime overhead. Reserve runtime conversion for interactive color pickers, theme preview tools, and other UX features that need instant feedback.
PostCSS plugins for build-time OKLCH conversion
postcss-preset-env includes a Color Level 4 transform that converts oklch() to HEX for older browsers while preserving the original oklch() for modern ones.5 Note that the standalone postcss-preset-env repository was archived in October 2023 and its plugins moved into the @csstools/postcss-plugins monorepo, so new projects should depend on that package instead. If your source CSS uses HEX and you want to convert to OKLCH at build time, a custom PostCSS plugin or a Style Dictionary transform handles the conversion. Style Dictionary's "css/oklch" transform reads HEX input tokens and writes oklch() output, which postcss-preset-env then processes into a dual-declaration with HEX fallback.
Use this when writing CSS and you need a color value in a format that a specific CSS function, SVG attribute, or browser API expects, particularly when your stylesheet mixes legacy HEX tokens with modern oklch() design tokens.
HEX brand color → CSS custom property in oklch()
#c8ff00
oklch(0.960 0.241 128.2)
Set --color-brand: oklch(0.960 0.241 128.2) in :root for Color Level 4 usage.
DevTools rgb() → HSL for shade ramp generation
rgb(59, 130, 246)
hsl(217, 91%, 60%)
Hold hue (217) and saturation (91%) fixed; vary lightness from 20% to 95%.
- 1.
W3C, "CSS Color Module Level 4: Color," w3.org, accessed June 2026. https://www.w3.org/TR/css-color-4/
- 2.
MDN Web Docs, "oklch() CSS function," developer.mozilla.org, accessed June 2026. https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/color_value/oklch
- 3.
Mozilla Developer Network, "color-mix() CSS function," developer.mozilla.org, accessed September 2026. https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/color_value/color-mix
- 4.
CSS-Tricks, "oklch()," css-tricks.com, accessed June 2026. https://css-tricks.com/almanac/functions/o/oklch/
- 5.
csstools, "postcss-preset-env," github.com, accessed September 2026. https://github.com/csstools/postcss-preset-env
For new projects targeting modern browsers, oklch() is the recommended format for design tokens because it produces perceptually consistent scales. HEX remains the best choice for compatibility with third-party tools, email, and SVG. HSL is a practical middle ground for projects that need human-readable tokens without full Level 4 adoption.
As of 2023, yes. Chrome 111+, Firefox 113+, Safari 15.4+, and Edge 111+ all support oklch() natively. Global support is above 90% for modern browsers. Internet Explorer does not support it.
Use the slash-separated form: oklch(0.612 0.212 261.5 / 0.5) for 50% opacity. The alpha can be expressed as a decimal (0–1) or a percentage (50%). This syntax is part of CSS Color Level 4 and works in all modern browsers that support oklch().
The browser ignores the oklch() declaration and falls back to the previous valid value for that property. Use @supports (color: oklch(0 0 0)) to provide HEX fallbacks conditionally.
No. All conversions run entirely in your browser using JavaScript. Nothing is uploaded to or stored on any server.
How CSS named color matching works
CSS defines 148 named colors, from the obvious anchors like black and white to oddities such as rebeccapurple and papayawhip.2 The CSS Named field finds the closest match for your current color, although closest here does not mean the smallest raw RGB distance. Colors like pink and brown can land on surprisingly similar red-green-blue triples while looking nothing alike to the human eye, which is exactly the kind of mismatch a purely numeric comparison gets wrong.
Why perceptual distance beats raw RGB
The matching algorithm measures perceptual distance in OKLab space, the same space that underpins OKLCH.5 Because that space mirrors how people actually judge color similarity, a muted red lands on firebrick rather than on a numerically close but visually distant alternative that a straight RGB comparison would pick. The small swatch displayed next to the field shows you exactly what the matched named color looks like, so you can judge how close the approximation is before you commit to copying it into your stylesheet.
Reading the WCAG contrast check
The contrast check compares text against your background using the contrast thresholds defined by the WCAG guidelines. The ratio scale starts at 1:1, where the text and background are indistinguishable, and climbs to a maximum of 21:1 for pure black text on a pure white background.6 The two panels in this tool show that ratio once with black text on your color and once with white text on your color, so you can immediately see which pairing gives you the more readable result.
The WCAG 2.1 thresholds are: AA requires 4.5:1 for normal text and 3:1 for large text (18pt or 14pt bold). AAA requires 7:1 for normal text and 4.5:1 for large text.6 AA LG means the 3:1 large-text threshold is met but not the 4.5:1 normal-text threshold. Fail means the ratio is below all thresholds.
TIP For body copy and any long-form reading, aim for at least the AA rating so the text stays legible across the widest range of devices. For small labels, captions, or placeholder text, targeting AAA gives you valuable headroom for readers with low vision or dim, uncalibrated screens. As a practical rule, the panel showing the higher contrast ratio is the safer text color choice for whatever interface is sitting on top of your selected background.
Building color scales with perceptually uniform spaces
Design systems require color scales where each step looks equally distant from the last, and OKLCH delivers exactly that because it operates in a perceptually uniform space. The same numeric step in any direction produces roughly the same perceived change, regardless of which hue you are working with, so you can step through lightness or chroma and trust that the visual result will feel evenly spaced from the darkest token to the lightest one.
Where HSL scales fall apart
HSL cannot make that guarantee, because equal numeric steps in lightness produce unequal perceived brightness differences across different hues. Yellow at 80% HSL lightness looks markedly brighter than blue at that same 80% value, which is why HSL-generated scales appear visibly unbalanced when you render several swatches side by side against a neutral background. That inconsistency gets worse at the extremes, where HSL bunches shades together near black and spreads them unevenly near white, making it hard to design a ramp where every step reads as an equal jump.
Building tokens and multi-step scales in OKLCH
Adjusting chroma in OKLCH also preserves hue identity far better than adjusting saturation in HSL does. Reducing HSL saturation on a vivid blue shifts the perceived hue slightly toward purple as the color desaturates, whereas reducing OKLCH chroma on that same blue produces a less vivid blue with essentially no hue drift. For design tokens where you need both a saturated primary and a tinted background variant of the same color, OKLCH chroma reduction keeps the relationship between those two versions consistent across your entire palette. Tailwind CSS v3 and Radix Colors both lean on perceptual models to generate their ramps for exactly this reason.
Building a ten-step scale in OKLCH by moving the L channel from 0.1 to 1.0 in equal intervals produces steps that look visually equidistant from dark to light, while the same ten steps in HSL compress awkwardly at the dark end and stretch at the bright end. Checking the OKLCH values in this converter alongside the HEX output keeps your token definitions anchored in a format any modern browser renders natively, so you can verify the perceptual spacing of a ramp as you build it without switching to a separate color science tool. The contrast check panel then confirms that both the light and dark ends of your scale clear the WCAG thresholds your design system demands for readable text on those backgrounds.
Convert HEX to HSL
HSL separates lightness from hue, which makes it the format for stepping a brand color lighter or darker without drifting into a neighboring hue, the basic move behind most HSL color scales. Paste the HEX code and the HSL field shows the hue angle, saturation and lightness; the guide below covers the conversion, shade ramps built in lightness steps and how HSL differs from Photoshop's HSB.
HSL (Hue, Saturation, Lightness) makes it easy to build color scales and adjust tones without losing the hue. When you have a brand HEX color and need a 10-step lightness scale for a UI, converting to HSL first gives you a predictable starting point.
How HEX to HSL conversion works
Converting HEX to HSL routes through an intermediate RGB step. Each HEX pair decodes to a 0–255 integer, then each channel normalizes to 0–1. From those three normalized values, the algorithm finds the maximum and minimum channel to determine lightness (their average), saturation (their spread divided by the complement of the lightness extremes), and hue (the position of the maximum channel on the 0–360 degree color wheel).1 Consequently, two colors with the same hue and saturation but different lightness share the same hue angle after conversion.
Why the conversion routes through RGB
HSL describes color in terms of perceptual qualities, not channel intensities. To derive hue, saturation, and lightness from three hex-encoded channels, the algorithm first converts to RGB because the relationship between channel values and the resulting hue angle is unambiguous in RGB space. Skipping the intermediate step would require a direct hex-to-HSL formula that is harder to verify and more prone to off-by-one errors in the hue calculation.
The intermediate RGB step also keeps the conversion deterministic across languages and libraries. Because the RGB-to-HSL math is identical everywhere, a value computed in JavaScript matches one computed in Python or a design tool, so the same HEX always yields the same hue, saturation, and lightness regardless of where the conversion runs. That cross-platform stability is why most color libraries route through RGB rather than inventing a bespoke HEX-to-HSL shortcut.
How the hue angle is calculated
The hue depends on which channel is the maximum and which is the minimum. If red is the maximum and blue is the minimum, the hue falls in the yellow-to-red range and is computed as (g - b) / (max - min), scaled to degrees. When green is the maximum, a different formula applies, and when blue is the maximum, yet another. The resulting angle wraps at 360 degrees, so a hue of 0 and a hue of 360 both represent pure red.
Where HEX to HSL conversion comes up
HSL is the format of choice for design token color scales. Starting from a brand HEX, converting to HSL gives a stable hue angle that stays fixed while lightness steps from 5% to 95% generate a full shade ramp. Building on this, CSS custom properties that define palette coordinates for hue and saturation let components construct hsl() values dynamically by referencing those property tokens. Yet any tool that only accepts HEX, including legacy build scripts and certain SVG renderers, requires converting the result back at the end.
Shade ramps for component states
A single brand color needs at least four visual variants for a complete component library: default, hover, active, and disabled. By holding the hue and saturation constant and stepping lightness down for hover and active, then desaturating slightly for disabled, you derive all four states from one HEX input without introducing hue drift. This approach keeps your component palette visually coherent across every button, link, and form field in the project.
When HEX input is the only option
Designers often deliver brand guidelines as HEX values because they are the most compact and universally supported format. If your CSS pipeline is built around HSL coordinates for dynamic theming, you need to convert those HEX brand values to HSL once during token generation and store the resulting hue, saturation, and lightness as your canonical design tokens. This one-time conversion step pays off every time a brand color changes, because you update a single HSL value and every component that references the custom properties updates automatically.
HEX to HSL edge cases and rounding
Achromatic colors, including pure greys, white, and black, have saturation zero and a mathematically undefined hue; most implementations output 0° by convention. Rounding floating-point intermediates introduces tiny errors in the hue angle, so a round-trip of HEX to HSL to HEX may differ by 1 in the last RGB channel digit. Furthermore, hsl() in CSS requires percentage suffixes on saturation and lightness, and omitting them produces invalid syntax in CSS 2.1 parsers, though CSS Color Level 4 allows space-separated unitless values in some contexts.2
Why achromatic hues are always zero
When all three RGB channels are equal, the color sits on the grey axis and has no saturation. The hue formula divides by (max - min), which becomes zero for greys, so the result is undefined. Every implementation picks 0° as the convention, which means the hue value for grey is arbitrary and should not be used as a meaningful identifier in your code.
Round-trip precision and when it matters
A round-trip through HSL introduces a small error because the HSL representation has finite precision (whole degrees for hue, whole percentages for saturation and lightness). For most UI work, a difference of 1 in one RGB channel is imperceptible. However, if you are generating a color palette programmatically and need every shade to match a reference exactly, store the original HEX value as the source of truth and derive HSL only for display or manipulation purposes.
Building accessible shade ramps with HSL lightness steps
HSL's lightness channel is the most reliable way to generate accessible shade ramps from a single brand color, and you can build a shade ramp from one HEX color by stepping lightness in the converter. Convert your brand HEX to HSL, then hold the hue and saturation constant while stepping lightness from 95% (near-white) down to 15% (near-black). Each step produces a shade that is perceptually related to the base color, which is essential for creating hover states, disabled states, and text-on-background combinations that meet WCAG contrast requirements.
The key insight is that equal lightness steps in HSL do not produce equal perceived brightness differences across all hues, because the L component is not accurate: different hues carry different real lightness values, which leads to contrast and accessibility surprises.3 Yellows at 60% lightness look brighter than blues at 60% lightness, an example of the Helmholtz-Kohlrausch effect where saturation is perceived as part of a color's brightness.4 For truly perceptually uniform ramps, convert to OKLCH and step the L channel instead. But for quick shade generation where exact perceptual uniformity is not critical, HSL lightness steps are good enough and supported in every browser without polyfills. Building on this, generate your ramp in HSL, then convert each step to HEX for use in your CSS custom properties.
CSS custom properties and dynamic HSL theming
HSL is the natural format for CSS custom property theming because you can decompose a color into its three channels and recompose them dynamically. Define custom properties for hue, saturation, and lightness in your :root, then reference those tokens inside hsl() throughout your stylesheet. To create a dark theme, override only the lightness custom property and every color that references those tokens updates automatically.
This pattern works best when you convert your brand HEX to HSL first and use the HSL coordinates as the canonical token values. Converting #3b82f6 to hsl(217, 91%, 60%) gives you the three channel values to store as separate custom properties. Building on this, CSS Color Level 4 allows space-separated hsl() syntax without commas: hsl(217 91% 60%).2 This is the recommended modern syntax because it works with the slash-separated alpha form: hsl(217 91% 60% / 0.5). The comma syntax is legacy and does not support alpha in a single function call.
HSL versus HSB: why CSS uses HSL and Photoshop uses HSB
CSS uses HSL (Hue, Saturation, Lightness) while Photoshop and most native OS color pickers use HSB (Hue, Saturation, Brightness, also called HSV).5 The two models share the same hue angle but define saturation and the third channel differently.1 In HSL, lightness 100% is always white regardless of saturation. In HSB, value 100% at saturation 0% is white, but value 100% at saturation 100% is the most vivid version of the hue.
This difference means you cannot directly copy HSB values from Photoshop into CSS hsl() and expect the same color. You must convert through an intermediate space (RGB or HEX) to get the correct HSL coordinates. Building on this, when a designer gives you HSB values from Photoshop, ask them to provide the HEX or RGB equivalent instead, or convert the HSB to RGB first and then to HSL. The converter on this tool accepts HEX, RGB, and HSL inputs directly, so you can paste any of these formats and get the HSL output without manual conversion.
Use this when building a design token color scale, creating hover and active state variants from a base color, or using CSS hsl() for dynamic theme generation.
Brand color → HSL for lightness scale
#c8ff00
hsl(74, 100%, 50%)
Adjust the third value (50%) up or down to create lighter or darker variants.
Primary button color → accessible hover state
#3b82f6
hsl(217, 91%, 60%)
For a darker hover, change 60% to 50%: hsl(217, 91%, 50%).
- 1.
"HSL and HSV," Wikipedia, en.wikipedia.org, accessed June 2026. https://en.wikipedia.org/wiki/HSL_and_HSV
- 2.
"hsl() CSS function," MDN Web Docs, developer.mozilla.org, accessed June 2026. https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/color_value/hsl
- 3.
Andrey Sitnik and Travis Turner, "OKLCH in CSS: why we moved from RGB and HSL," evilmartians.com, September 2025. https://evilmartians.com/chronicles/oklch-in-css-why-quit-rgb-hsl
- 4.
"Helmholtz-Kohlrausch effect," Wikipedia, en.wikipedia.org, accessed August 2026. https://en.wikipedia.org/wiki/Helmholtz%E2%80%93Kohlrausch_effect
- 5.
Adobe, "Choose colors with Adobe Color Picker," helpx.adobe.com, February 2026. https://helpx.adobe.com/photoshop/desktop/adjust-color/choose-colors/choose-colors-with-the-adobe-color-picker.html
Hue is a position on the color wheel expressed as degrees (0–360). 0 and 360 are red, 120 is green, 240 is blue. 74° is a yellow-green, which is why a lime color like #c8ff00 maps to 74°.
Yes for adjustments. Increasing the lightness value makes any hue lighter in a predictable way. Doing the same in RGB means changing three separate values with no guarantee of a matching hue.
HSL and RGB represent the same color, and the conversion is lossless for integer RGB values. If the rendered color looks different, check whether your tool interprets hsl() with percentage saturation and lightness or fractional values.
No. CapyToolkit runs every HEX-to-HSL conversion locally in your browser using JavaScript, and nothing you type is ever stored, logged, or transmitted anywhere.
For whole-number RGB inputs, the round-trip is nearly lossless, though you may see a difference of 1 in one channel due to the finite precision of the HSL representation. If you need a perfectly reversible pipeline, keep the original HEX value as the source of truth and derive HSL only when you need to adjust the hue, saturation, or lightness for a specific design task.
Convert RGB to HSL
Darkening a color by editing three RGB channels at once tends to shift its
hue, while lowering HSL lightness keeps the hue fixed and changes only how
light the color looks. Entering an rgb() value fills the HSL
field, and the guide below covers the conversion formula, a full scale from
one RGB value, alpha channels and the result inside color-mix()
and relative color syntax.
RGB integers do not expose intuitive editing handles.
When a developer needs to darken a button by 10%, adjusting all three RGB channels independently risks shifting the perceived hue unintentionally. Converting to HSL first isolates the lightness value so it can be changed alone: the hue angle and saturation stay fixed, and the color family stays visually consistent through adjustments. This separation between identity (hue) and intensity (lightness) is the core reason HSL exists as a design-facing format.
How RGB to HSL conversion works
Converting RGB to HSL begins by normalizing each 0–255 integer to a 0–1 float. The algorithm identifies the maximum and minimum channel values. Lightness is their average. Saturation measures the channel spread relative to the lightness distance from the extremes: above lightness 0.5, it uses (max − min) / (2 − max − min); below 0.5, it uses (max − min) / (max + min). Hue maps the maximum channel to its 0–360 sextant position, with the secondary channels determining the fractional offset within that sextant.1
Why saturation depends on lightness
The saturation formula branches at lightness 0.5 because the same channel spread looks different depending on how bright the color is. When you compare a 10-unit channel spread on a dark color versus the same spread on a light color, the dark one appears more saturated to the eye because the smaller absolute values create a larger relative difference. By normalizing relative to the lightness extremes, the dual formula ensures consistent saturation percentages regardless of where the color sits on the lightness scale.
The branching formula also protects you from surprising results when you build scales. A mid-tone and a highlight of the same hue can both register low saturation, but only the branch above lightness 0.5 keeps the percentage meaningful as colors approach white. Keeping the math tied to the lightness extremes means a tint and its base shade report saturation values that actually compare, instead of drifting apart as the color gets brighter.
Where RGB to HSL conversion comes up
Browser DevTools and JavaScript color pickers emit rgb() values. Canvas getImageData() returns raw r, g, b integers per pixel.2 Consequently, any pipeline that begins by reading color from a rendered surface and needs to derive a lighter or darker variant must pass through HSL. Building on this, CSS color-mix() and color() functions can express similar transformations natively in modern browsers, but server-side and legacy environments that do not support CSS Color Level 4 still require the explicit RGB-to-HSL step in JavaScript.
Reading pixel colors from a canvas
When you sample a pixel from an HTML canvas using getImageData(), the returned data is always an RGBA quadruplet of 0–255 integers. If your application needs to determine whether a pixel is warm or cool, or whether it falls within a specific hue range for a color-based selection tool, converting those RGB integers to HSL gives you the hue angle directly. This is particularly useful for image analysis features like background removal or color-based masking, where the hue channel provides a more reliable signal than raw RGB values.
RGB to HSL edge cases and rounding
Achromatic inputs (r, g, and b all equal) produce saturation 0. The hue angle is mathematically undefined for grey; most implementations return 0° by convention.1 Floating-point division in the saturation formula produces values rounded to two decimal places. Yet a round-trip of RGB → HSL → RGB may return an integer 1 different in one channel because of this rounding.3 Alpha channels in rgba() are not part of the HSL model and must be tracked separately through any workflow that modifies HSL values.
Handling grey in design token pipelines
When your design system generates color scales programmatically, grey edge cases appear more often than you might expect. A color like rgb(128, 128, 128) converts to hsl(0, 0%, 50%), where the hue of 0° is arbitrary. If you later rotate the hue to create a warm variant, the original grey will shift to red instead of remaining neutral. The safe approach is to check whether saturation rounds to zero before applying hue-based transformations, and treat those colors as fixed neutrals that should not participate in hue rotation logic.
Generating color scales from a single RGB value
Converting an RGB color to HSL gives you the coordinates you need to generate a full shade scale. Take the hue and saturation from the HSL output, then create variants by stepping lightness from 95% down to 10% in equal increments. Each step is a visually related shade of the original color, suitable for building button hover states, card backgrounds, and text color hierarchies.
A practical 10-step scale uses lightness values of 97%, 93%, 88%, 80%, 70%, 58%, 46%, 35%, 24%, and 14%. These values are not evenly spaced because HSL lightness is not perceptually uniform: the steps are compressed at the light and dark ends to avoid colors that look too similar.4 Building on this, after generating the HSL scale, convert each step to HEX for use in CSS custom properties. The resulting palette is hue-consistent (all shades share the same hue angle) and saturation-consistent (all shades share the same saturation percentage), which gives the palette a cohesive visual identity.
RGB to HSL for CSS color-mix() and relative color syntax
CSS Color Level 4 introduces color-mix() and relative color syntax, both of which work in a specified color space.5 color-mix(in hsl, rgb(59, 130, 246), white) mixes your RGB color with white in HSL space, producing a lighter tint. The relative color syntax goes further: from rgb(59, 130, 246) calc(l + 0.1) c h takes the HSL equivalent and increases lightness by 10 percentage points.
These CSS features require the browser to internally convert RGB to HSL (or whatever space you specify). By converting explicitly first, you can preview the HSL coordinates and predict what the CSS functions will produce. Building on this, the in hsl keyword in color-mix() is important: mixing in HSL produces different results than mixing in sRGB or OKLCH because the interpolation happens in different color spaces. HSL mixing tends to produce more perceptually intuitive results for tints and shades, while OKLCH mixing produces the most perceptually uniform gradients.6
Handling alpha channels when converting RGB to HSL
The HSL color model has no alpha channel. When you convert rgba(59, 130, 246, 0.5) to HSL, the alpha value is discarded and you get hsl(217, 91%, 60%) with no transparency information. To preserve alpha, you must track it separately and reapply it after the HSL conversion. In CSS, this means using hsla() instead of hsl(): hsla(217, 91%, 60%, 0.5).
CSS Color Level 4 introduces slash-separated alpha syntax for hsl(): hsl(217 91% 60% / 0.5).5 This is the recommended modern form because it is consistent with other CSS color functions and works with color-mix(). Building on this, if your workflow involves converting rgba() to HSL and back, always store the alpha value alongside the HSL coordinates as a separate variable. Losing the alpha during conversion is a common source of bugs in design token pipelines that treat color as a single value rather than as a combination of color coordinates and opacity.
Use this when you need lighter, darker, or more saturated variants of an existing RGB color: hold the hue and saturation fixed while stepping lightness to darken a button without shifting its hue.
Button color → hover state derivation
rgb(59, 130, 246)
hsl(217, 91%, 60%)
Set lightness to 50% for a darker hover: hsl(217, 91%, 50%).
Canvas pixel → design token
rgb(200, 100, 50)
hsl(20, 60%, 49%)
Round lightness to 50% for a clean palette token baseline.
- 1.
"HSL and HSV," Wikipedia, en.wikipedia.org, accessed June 2026. https://en.wikipedia.org/wiki/HSL_and_HSV
- 2.
WHATWG, "HTML Standard," html.spec.whatwg.org, accessed August 2026. https://html.spec.whatwg.org/dev/canvas.html#pixel-manipulation
- 3.
Martin R, "Is there a way to prevent from precision lossing from converting from RGB, to HSV then back to RGB?," Stack Overflow, stackoverflow.com, February 2022. https://stackoverflow.com/questions/71071103/
- 4.
Andrey Sitnik and Travis Turner, "OKLCH in CSS: why we moved from RGB and HSL," evilmartians.com, September 2025. https://evilmartians.com/chronicles/oklch-in-css-why-quit-rgb-hsl
- 5.
"hsl() CSS function," MDN Web Docs, developer.mozilla.org, accessed June 2026. https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/color_value/hsl
- 6.
"color-mix() CSS function," MDN Web Docs, developer.mozilla.org, accessed August 2026. https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/color_value/color-mix
Subtracting from all three RGB channels shifts the hue as well as the brightness. In HSL, decreasing only the lightness keeps the hue angle and saturation identical, producing a visually darker shade of the same color rather than a different one.
Hue is a 0–360 degree angle on the color wheel. Red sits at 0° and 360°, green at 120°, blue at 240°. Yellow maps to 60°, cyan to 180°, and magenta to 300°. Values between these primaries map continuously around the wheel.
Yes. hsl(217, 91%, 60%) is valid CSS. Modern browsers also support the space-separated form: hsl(217 91% 60%). Both accept an optional alpha: hsl(217 91% 60% / 0.5) for a semi-transparent variant.
No. CapyToolkit converts your RGB values to HSL entirely in your browser using JavaScript, so nothing you type or paste is sent to any server at any point.
The conversion is exact within floating-point precision. Final HSL values round to two decimal places for display. A round-trip of RGB → HSL → RGB may return an integer 1 off in one channel due to rounding in the intermediate saturation and lightness formulas.
Convert HSL to HSV
HSL and HSV share the same hue angle but encode brightness differently: 100%
lightness in HSL is always white, while 100% value in HSV is the brightest
version of the hue. That difference is why the saturation number changes when
you move a color between a CSS hsl() token and a Photoshop or
color picker HSV value, which the guide below works through step by step.
HSL and HSV share a hue angle but differ in how they encode brightness.
In HSL, a lightness of 100% always produces white, regardless of saturation, while a lightness of 50% at full saturation gives the most vivid version of the hue. In HSV, value 100% at full saturation gives the vivid color; white requires both value 100% and saturation 0%. This structural difference means the same color has different coordinates in each model, requiring explicit conversion when moving between tools that use each system.
How HSL to HSV conversion works
Converting HSL to HSV routes through intermediate lightness and chroma calculations. From the HSL lightness (L) and saturation (S), the algorithm computes the chroma C = S × (1 − |2L − 1|). From chroma and lightness, value V = L + C/2. Saturation in HSV is then S_hsv = C/V when V > 0, and 0 when V equals 0.1 The hue angle is identical in both models (no conversion is needed for that channel) because both HSL and HSV use the same 0–360 degree color wheel definition.
Why chroma matters in the conversion
Chroma represents the distance from the grey axis to the most saturated color at a given hue and lightness. It acts as the bridge between the two models because HSL and HSV both derive their third channel from chroma but apply it differently. In HSL, chroma determines how far the color deviates from the midpoint of lightness. In HSV, chroma determines how far the color deviates from black. Understanding this shared intermediate makes it clear why the two models produce different saturation and brightness coordinates for the same color.
Using chroma as the bridge also keeps the conversion exact for achromatic colors. When saturation is zero in HSL, the chroma is zero, so the computed value collapses to the HSL lightness with no residual color, which matches how black and white behave in HSV. That clean collapse is why the same formula works from the most vivid hue down to pure grey without a separate code path for achromatic inputs.
Where HSL to HSV conversion comes up
Graphics APIs and native OS color pickers often use HSV rather than HSL. Photoshop's color picker reports HSB (which is identical to HSV: the "B" stands for brightness, a synonym for value). Many OpenCV and image processing functions accept HSV natively. Consequently, converting HSL design tokens to HSV is a common step when a web workflow feeds into a desktop graphics pipeline. Furthermore, color picker UI components in JavaScript (react-colorful, pickr, and others) internally use HSV to determine the position of the gradient thumb.2
When web and desktop pipelines intersect
A typical crossover happens when a design system defines colors as HSL tokens for CSS, but the same colors must be entered into a desktop image editor like Photoshop or Affinity Designer. Those applications expose an HSB/HSV picker, not an HSL one. Rather than manually approximating values, match an HSL token to Photoshop's HSB fields once during handoff, which eliminates guesswork and ensures the color rendered on the web page matches what the designer sees in their editing tool.
HSL to HSV edge cases and rounding
Achromatic inputs (HSL saturation 0) produce HSV saturation 0 regardless of value; the hue remains 0° by convention. HSL lightness 100% (white) converts to HSV value 100% and saturation 0%. HSL lightness 0% (black) converts to HSV value 0% and saturation 0%. Intermediate rounding may shift saturation by 0.1–0.2 percentage points. Building on this, any round-trip of HSL → HSV → HSL should validate against the original rather than assuming perfect reversibility for non-integer input values.
Why pure white and pure black behave differently
In HSL, white (lightness 100%) and black (lightness 0%) are the only two points where saturation has no visible effect. When you convert these to HSV, the saturation drops to 0% and the value matches the lightness extremes. This matters when you are building a color scale that includes both endpoints: a scale from hsl(217, 91%, 0%) through hsl(217, 91%, 100%) will have correct HSV saturation at the midpoint but zero saturation at both ends, which means any hue rotation you apply at the extremes will have no visible effect.
Why Photoshop uses HSB and how to match its values
Photoshop's color picker displays HSB (Hue, Saturation, Brightness) values, which are identical to HSV under a different name.3 When a designer gives you HSB values from Photoshop (for example, H: 217, S: 76%, B: 96%), you can use them as direct HSV input. The conversion from HSL to HSV is necessary because your CSS design tokens likely use HSL, and the Photoshop values are in a different color model.
The structural difference between HSL and HSV is in how they handle lightness versus value. HSL lightness 50% at full saturation gives the most vivid color; HSV value 100% at full saturation gives the same vivid color. But HSL lightness 75% produces a pastel, while HSV value 100% at a lower saturation also produces a pastel, through a different numeric path. Building on this, when you convert an HSL design token to HSV for Photoshop input, the saturation and brightness values will be different from the HSL saturation and lightness, even though the resulting color is the same. This is expected and correct.
OpenCV color space conversions and HSV ranges
OpenCV uses HSV with a specific range: H is 0–180 (not 0–360), S is 0–255, and V is 0–255.4 This is a quirk of the library's 8-bit integer representation, which halves the hue range to fit in a single byte. When you convert HSL to HSV for use in OpenCV, you must scale the hue angle by dividing by 2 and scale saturation/value to 0–255 instead of 0–100%.
For example, hsl(217, 91%, 60%) converts to hsv(217, 76%, 80%) in standard HSV. In OpenCV's representation, this becomes H: 108 (217 / 2), S: 194 (76% of 255), V: 204 (80% of 255). Building on this, if you are building a web interface that lets users pick colors in HSL and then processes images with OpenCV on the backend, the conversion pipeline is: HSL → standard HSV → OpenCV HSV (with range scaling). Getting the scaling wrong produces colors that are visibly wrong, so test with known reference values before deploying.
JavaScript color picker internals: why most use HSV
Most JavaScript color picker libraries (react-colorful, pickr, Spectrum) use HSV internally for their color space model.5 The reason is that HSV maps naturally to the visual layout of a color picker: the hue is represented as a vertical or circular gradient, the saturation as a horizontal axis (from grey to full color), and the value as a vertical axis (from black to full brightness). This three-dimensional layout is intuitive for users and straightforward to implement with CSS gradients.
When you initialize a color picker with an HSL value, the library converts HSL to HSV internally, then uses the HSV coordinates to position the picker's thumbs and gradients. The conversion happens once at initialization. Building on this, if you are building a custom color picker and want to accept HSL input, you need to implement the HSL-to-HSV conversion yourself or use a library like culori that provides it. The converter on this tool performs this conversion and displays the HSV output, which you can then pass directly to your color picker's initialValue prop.
Use this when transferring a color defined in HSL to an API, library, or design tool that accepts only HSV (or HSB) coordinates, most notably Photoshop, OpenCV, and JavaScript color picker components.
CSS HSL token → Photoshop HSB input
hsl(74, 100%, 50%)
hsv(74, 100%, 100%)
In Photoshop, H/S/B fields map directly to these HSV values.
Hover state HSL → color picker library init
hsl(217, 91%, 50%)
hsv(217, 97%, 80%)
Pass the HSV triple to color picker initializers that use the HSV model.
- 1.
"HSL and HSV," Wikipedia, en.wikipedia.org, accessed June 2026. https://en.wikipedia.org/wiki/HSL_and_HSV
- 2.
simonwep, "pickr/README.md," github.com, accessed September 2026. https://github.com/simonwep/pickr/blob/master/README.md
- 3.
Adobe, "Choose colors with Adobe Color Picker," helpx.adobe.com, February 2026. https://helpx.adobe.com/photoshop/desktop/adjust-color/choose-colors/choose-colors-with-the-adobe-color-picker.html
- 4.
OpenCV, "Changing Colorspaces," docs.opencv.org, accessed June 2026. https://docs.opencv.org/4.x/df/d9d/tutorial_py_colorspaces.html
- 5.
omgovich, "react-colorful/src/hooks/useColorManipulation.ts," github.com, accessed June 2026. https://github.com/omgovich/react-colorful/blob/master/src/hooks/useColorManipulation.ts
Nothing. HSB (Hue, Saturation, Brightness) and HSV (Hue, Saturation, Value) are the same color model under two different names. Photoshop uses HSB; most programming APIs use HSV. The coordinates are identical and require no conversion between the two names.
The two models define saturation differently. In HSL, saturation 100% at lightness 50% gives the most vivid color. In HSV, saturation 100% at value 100% gives the same vivid color. For lighter or darker tones, the HSV saturation is lower: the same hue looks less saturated because the definition of saturation references a different denominator.
Not directly. CSS does not have an hsv() function. To use HSV values in CSS, convert them to HSL (the reverse of this converter) or to RGB/HEX first.
Yes, within floating-point precision. The hue angle is preserved exactly. Saturation and value may differ by less than 0.1 percentage points from the theoretical result due to floating-point arithmetic, but a round-trip produces the original HSL values to within that tolerance.
No. CapyToolkit runs all HSL-to-HSV conversions entirely in your browser using JavaScript. Nothing is sent to any server, and nothing is stored between sessions.
WCAG 2.1 Contrast Rating Thresholds
- AA normal / large text 4.5:1 / 3:1
- AAA normal / large text 7:1 / 4.5:1
- AA LG Meets 3:1 large-text but not 4.5:1 normal-text
Pick your own color above and check the contrast panel's rating against these thresholds.
- 1.
Mozilla Developer Network, "<hex-color> CSS type," developer.mozilla.org, April 2026. https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/hex-color
- 2.
W3C, "CSS Color Module Level 3," w3.org, January 2022. https://www.w3.org/TR/css-color-3/
- 3.
Microsoft Learn, "HSV Color Spaces," learn.microsoft.com, December 2021. https://learn.microsoft.com/en-us/windows/win32/wcs/hsv-color-spaces
- 4.
Mozilla Developer Network, "oklch() CSS function," developer.mozilla.org, accessed June 2026. https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/color_value/oklch
- 5.
Andrey Sitnik, "OKLCH in CSS: why we moved from RGB and HSL," evilmartians.com, September 2025. https://evilmartians.com/chronicles/oklch-in-css-why-quit-rgb-hsl
- 6.
W3C, "Web Content Accessibility Guidelines (WCAG) 2.1," w3.org, May 2025. https://www.w3.org/TR/WCAG21/