What Is a HEX Color?
A HEX color is a six-character string encoding a color as three base-16 channel values. Originally adopted from X11 and HTML 2.0, HEX became the default color format for web browsers, CSS, and design tools because it is compact, unambiguous, and paste-friendly across virtually every platform that processes color.1 Understanding how the format encodes red, green, and blue channels explains both its advantages and the scenarios where a more explicit format serves better.
What is a HEX color?
#f50 for #ff5500) when both digits in each pair are identical.Why HEX became the dominant web color format
HEX predates CSS. The format entered the web through HTML's bgcolor and color attributes in the early 1990s, borrowed from the X11 color system.1 Browsers adopted it because the six-character string is unambiguous: there is no confusion between comma-separated values, no unit suffixes, and no whitespace sensitivity. Designers and developers paste HEX codes into CSS files, SVG attributes, HTML attributes, Figma fields, and Slack messages with full confidence that the color will render identically everywhere. That portability is exactly why HEX remains the safest format to copy from one tool to another, even as more expressive formats have arrived.
Shorthand and alpha-channel extensions
Shorthand HEX (#rgb) is valid only when each channel pair consists of two identical digits. #f50 expands to #ff5500, and #abc expands to #aabbcc. This restriction means only 4,096 of the 16.7 million possible colors have a shorthand form, which is why shorthand is useful for quick prototyping but unreliable for precise color work. For alpha-channel transparency, an eighth character pair appends to the standard six: #rrggbbaa, where aa follows the same 00–ff scale (00 is fully transparent, ff is fully opaque).3 CSS Color Level 4 added support for 4-digit (#rgba) and 8-digit (#rrggbbaa) HEX notation, yet some older tools and email clients still reject anything beyond the classic 6-digit form.
When to use HEX versus other formats
HEX is the best choice for any value that crosses tool boundaries: design handoffs, documentation, email HTML, and SVG files all benefit from its compact, unambiguous form. When you need to darken a color or build a shade scale by adjusting a single channel, HSL or OKLCH give more intuitive editing handles because you can change lightness without affecting hue or saturation. Canvas APIs and WebGL shaders work more directly with RGB integers. For new CSS design systems targeting perceptual uniformity, oklch() is the modern recommendation. Yet for the broadest compatibility across the widest range of tools, HEX remains the universal fallback that every browser, editor, and chat platform recognizes without reformatting.
How HEX encodes color at the byte level
A HEX color code maps directly to three bytes of binary data. The #rrggbb string represents six hexadecimal digits, where each pair is one byte: the first byte is red, the second is green, the third is blue. In memory, #3b82f6 occupies three bytes: 0x3b (59 in decimal), 0x82 (130), and 0xf6 (246).2 This direct byte mapping is why HEX is the most efficient color format for storage and transmission: it requires no parsing beyond hex-to-decimal conversion, and the six-character string is shorter than any comma-separated or function-call alternative.
HEX in binary file formats
PNG, JPEG, and GIF files store pixel data as raw RGB triplets, not as HEX strings. The HEX representation is a human-readable encoding of the same three bytes. When a PNG file stores a pixel as the bytes 3b 82 f6, a color picker displays it as #3b82f6. Understanding this equivalence helps when you work with binary image data in JavaScript TypedArrays: a Uint8Array containing [0x3b, 0x82, 0xf6] is the same color as #3b82f6, and converting between the two is a matter of formatting the integers as two-digit hex pairs.
The byte-level view also explains why a color picker can show a HEX value instantly while a format like rgb() requires tokenizing three numbers. There is no comma to split and no range to validate beyond the fixed width, so the conversion to the three underlying bytes is a direct lookup. That same property is why image-editing libraries expose HEX alongside the raw bytes: the two representations are trivially convertible, and picking one or the other is mostly a matter of what the surrounding code expects.
The origin of HEX colors in web history
HEX colors entered the web through the HTML 3.2 specification in 1997, which defined the bgcolor and color attributes as accepting #rrggbb values. The format was borrowed from the X11 Window System's color database, which used hex triplets to name colors in its rgb.txt file.4 Before HEX, early web browsers supported only named colors (limited to the original 16 CSS1 names) or decimal rgb() notation. HEX won adoption because it was more compact than rgb(59, 130, 246) and less ambiguous than named colors, which varied across browser implementations.
Why HEX survived the transition to CSS3 and CSS4
Every new CSS color format since HEX has been additive: CSS2 added rgb(), CSS3 added rgba() and hsl(), CSS4 added oklch() and color().3 None of these replaced HEX because HEX serves a specific role as the most portable, most compact, and most paste-friendly format. Design tools default to HEX for copy output, Slack and GitHub render HEX as color swatches, and every browser that has ever supported CSS still parses #rrggbb. New formats add expressive power, but HEX remains the universal interchange format because nothing else matches its combination of brevity and universal support.
Comparing HEX to other compact color encodings
Base64 encoding can represent the same three RGB bytes in four characters instead of six (plus the # prefix), but Base64 color codes never gained traction because they are not human-readable and offer no advantage in contexts where the #rrggbb string is already short enough. CSS shorthand HEX (#rgb) reduces the length to four characters but only works for 4,096 of the 16.7 million possible colors. Three-digit HEX is useful for rapid prototyping where exact color values do not matter, but production CSS should always use the six-digit form for precision.
HEX in version control and code review
HEX colors are easy to diff in version control because a color change appears as a single token replacement: #3b82f6 becoming #2563eb is a clear, atomic change in a git diff. Formats like rgb(59, 130, 246) produce noisier diffs when individual channels change. For design system codebases where color values change frequently during token refinement, HEX produces cleaner commit histories that are easier to review and revert. CapyToolkit does not store any HEX values you enter during conversion or lookup.
Try in the tool
Open the Color Format Converter tool pre-filled to a HEX color to verify it or try a different one.
Check a HEX color in the tool →- 1.
"Web colors," Wikipedia, en.wikipedia.org, accessed June 2026. https://en.wikipedia.org/wiki/Web_colors
- 2.
Mozilla Developer Network, "<hex-color> CSS type," 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," w3.org, accessed June 2026. https://www.w3.org/TR/css-color-4/
- 4.
W3C, "HTML 3.2 Reference Specification," w3.org, January 1997. https://www.w3.org/TR/1997/REC-html32-19970114/
The # prefix signals that the following characters are a hexadecimal color value. It is required in CSS color properties and HTML color attributes. Some tools (Figma, Sketch) strip it in their UI but reattach it when you copy the value as CSS.
Only in shorthand form (#rgb), where each of the three channels is represented by a single digit that implies a repeated pair. #f50 means #ff5500. This abbreviation works only for 6-character HEX values where both digits of each pair are identical, so most colors cannot use shorthand.
Both encode the same information. #rrggbbaa is more compact and pastes as a single token. rgba(r, g, b, a) is more readable because the alpha is clearly visible as a separate argument. CSS supports both forms, but email HTML clients vary in their support for 8-digit HEX, so test thoroughly before relying on it in email templates.
No. #3B82F6 and #3b82f6 are identical in CSS. Most linters enforce one case consistently, so check your project's style guide for the convention. Tools like Prettier and Stylelint can auto-enforce lowercase hex across your codebase.
No. CapyToolkit processes all color lookups and conversions locally in your browser. Nothing is stored or transmitted to any server.
What Is HSL?
HSL stands for Hue, Saturation, Lightness. It describes color the way designers think about it rather than the way displays render it. Introduced in CSS Color Module Level 3 via the hsl() function, it made CSS colors editable without knowing how red, green, and blue channel values interact1. Unlike RGB or HEX, where brightening a color requires increasing multiple channel values in careful proportion, HSL lets you adjust the lightness axis alone while the hue and colorfulness stay fixed2.
What is HSL?
How HSL differs from RGB and HEX
RGB and HEX encode color as additive light intensities, where the numbers describe how bright each phosphor glows rather than what the color communicates as a design decision. HSL inverts this model by starting from human perception: you name the color family (hue), state how vivid it is (saturation), and state how light or dark it is (lightness)2. For a developer who wants a lighter version of a button color, HSL eliminates the guesswork.
Why HSL reads closer to design intent
Instead of calculating how a 10% lightness increase on #3b82f6 translates into specific channel integers, you adjust the L channel and the result is predictable. HSL also preserves hue and saturation as you move up or down the lightness scale, so a brand blue at 60% lightness and the same blue at 30% lightness feel like members of the same color family without any manual fine-tuning.
The predictable channel behavior is also why HSL scales survive review better than RGB scales. When a reviewer sees a token at hsl(217, 91%, 30%), they can immediately reason about how dark it is relative to the base, while an RGB triple hides that relationship behind three channel numbers. That readability is the main reason HSL became the default notation for hand-authored design tokens before OKLCH arrived, and it still holds up for teams that prefer thinking in hue and lightness.
Where HSL is most useful
HSL is the natural format for design token color scales. A brand color defined as hsl(217, 91%, 60%) can generate ten shade variants by holding hue (217) and saturation (91%) fixed while stepping lightness from 10% to 95%. Yet HSL has a known flaw: equal lightness steps do not produce equal perceived brightness differences across hue angles3. A yellow at 50% HSL lightness looks substantially brighter than a blue at the same value. Building on this, OKLCH addresses this issue and is now recommended for perceptually uniform scales, while HSL remains practical for maintainable CSS variables in projects that do not require strict perceptual precision.
HSL in modern CSS syntax
CSS Color Level 4 updated hsl() to accept space-separated values without commas: hsl(217 91% 60%) alongside the original comma form hsl(217, 91%, 60%)4. Both forms are valid in modern browsers, so you can adopt the cleaner space-separated syntax without breaking older engines. Alpha is added with a slash-separated fourth value: hsl(217 91% 60% / 0.5) produces 50% opacity. Relative color syntax goes further by letting you derive related colors directly in CSS: color(from hsl(217 91% 60%) hsl h s calc(l - 10%)) produces a 10%-darker variant without JavaScript4. HSL is one of the most forward-compatible legacy formats because it integrates naturally with CSS Level 4 relative color expressions.
HSL for CSS animations and transitions
HSL is the most practical format for CSS color animations because its channels map directly to animatable properties5. Transitioning from hsl(217, 91%, 60%) to hsl(217, 91%, 40%) produces a smooth darkening effect with no hue shift, which is exactly what you want for a button press animation. Animating in RGB causes a subtle desaturation at the midpoint because the gamma curve distorts the interpolation. Animating in HSL keeps saturation and lightness independent, so each channel moves linearly from start to end without perceptual side effects.
Using HSL in @keyframes for color cycling
A hue-cycling animation that rotates through the full color wheel is trivial in HSL: @keyframes hue-spin { from { background: hsl(0, 100%, 50%); } to { background: hsl(360, 100%, 50%); } }5. The browser interpolates the hue channel from 0 to 360 degrees, producing a smooth rainbow cycle. Achieving the same effect in RGB requires animating all three channels simultaneously with carefully chosen curves, and the result passes through desaturated midpoints. HSL's hue channel makes this pattern a two-line keyframe block.
HSL versus OKLCH for design system tokens
HSL remains a practical choice for design system tokens when your team is already familiar with it, when you need to support browsers older than 2023, or when the perceptual non-uniformity of HSL is acceptable for your use case. OKLCH is the better choice when you need perceptually equidistant shade scales, when you are building a new system from scratch, or when your browser support matrix is 2023+3. Both formats support the same CSS syntax patterns (custom properties, relative color, color-mix()), so the choice of format does not constrain your architecture.
Converting HSL tokens to OKLCH during migration
When migrating existing HSL tokens to OKLCH, convert each token individually and compare the before and after values. Most HSL colors convert to OKLCH with minimal visual difference, but colors at extreme lightness values (below 10% or above 95%) may show noticeable shifts because OKLCH and HSL define lightness differently. Audit your darkest and lightest tokens after conversion to ensure they still meet contrast requirements and look correct in context. CapyToolkit runs all conversions locally in your browser, so no token data is transmitted during the migration process.
Try in the tool
Open the Color Format Converter tool pre-filled to HSL to verify it or try a different one.
Check HSL in the tool →- 1.
W3C, "CSS Color Module Level 3," w3.org, January 2022. https://www.w3.org/TR/css-color-3/#hsl-color
- 2.
"HSL and HSV," Wikipedia, accessed June 2026. https://en.wikipedia.org/wiki/HSL_and_HSV
- 3.
W3C, "CSS Color Module Level 4," w3.org, June 2026. https://www.w3.org/TR/css-color-4/
- 4.
Mozilla Developer Network, "hsl() CSS function," developer.mozilla.org, accessed June 2026. https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/hsl
- 5.
Mozilla Developer Network, "@keyframes CSS at-rule," developer.mozilla.org, accessed June 2026. https://developer.mozilla.org/en-US/docs/Web/CSS/@keyframes
0° (and 360°, which wraps back to the same point). The color wheel used by HSL places red at 0°, yellow at 60°, green at 120°, cyan at 180°, blue at 240°, and magenta at 300°.
Saturation 0% at any lightness produces grey because the hue is removed and only the brightness remains. Lightness 0% produces black regardless of hue and saturation, since there is no light. Lightness 100% produces white for the same reason.
Yes. hsl() has been supported in all major browsers since 2008. The space-separated comma-free syntax (hsl(217 91% 60%)) requires modern browsers: Chrome 65+, Firefox 60+, Safari 12.1+.
When building color scales where each step should look perceptually equidistant. In HSL, yellows appear lighter than blues at the same L value. OKLCH corrects this: equal L steps look equally bright across all hues. If your project targets modern browsers and values perceptual accuracy, use OKLCH for palette tokens and HSL for one-off adjustments.
No. All conversions run locally in your browser. Nothing is sent to or stored on any server.
What Is OKLCH?
OKLCH is a perceptually uniform color model where equal numeric steps produce roughly equal perceived color differences1. Developed by Björn Ottosson in 2020 and incorporated into CSS Color Level 4, it addresses a longstanding problem with HSL: equal lightness values in HSL do not look equally bright across different hue angles, making it unreliable for generating accessible color scales. OKLCH solves this by grounding its three channels (lightness, chroma, and hue) in a model calibrated to human visual perception.
What is OKLCH?
oklch() CSS function uses these three coordinates directly: oklch(0.612 0.212 261.5) is the perceptual representation of the blue commonly known as Tailwind blue-500.Why OKLCH is better than HSL for color scales
In HSL, two colors can have the same L value but look dramatically different in brightness. A yellow at hsl(60, 100%, 50%) looks much lighter than a blue at hsl(240, 100%, 50%), even though both have L = 50%. This happens because HSL's lightness axis is not calibrated to human perception. It reflects raw sRGB channel averages rather than perceived luminosity. OKLCH corrects this by defining lightness in OKLab, a space where equal L steps produce roughly equal perceived brightness differences across all hue angles. Consequently, a color scale built in OKLCH by stepping L from 0.95 to 0.20 while holding H and C constant will look visually equidistant at every step.
OKLCH in CSS and browser support
CSS Color Level 4 includes oklch() as a first-class color function2. Chrome 111+, Firefox 113+, Safari 15.4+, and Edge 111+ all support it natively, covering over 90% of global browser traffic3. Using oklch() in production CSS requires no polyfill for modern browser targets. Tailwind CSS v4 defines its entire built-in palette in OKLCH4. CSS relative color syntax integrates naturally with oklch(): color(from oklch(0.612 0.212 261.5) oklch calc(l + 0.1) c h) produces a lighter variant in pure CSS without JavaScript. Because oklch() is now the recommended format for new design systems, learning it today means your token architecture will remain current as the CSS ecosystem evolves.
Limitations and practical trade-offs
OKLCH coordinates are less intuitive than HSL for designers accustomed to sliders. The chroma channel has no fixed maximum, and what counts as fully saturated varies by hue and lightness rather than following a predictable 100% ceiling. Designers who rely on HSL sliders often find OKLCH values harder to estimate visually without a reference chart.
When OKLCH is worth the learning curve
Wide-gamut colors (P3, Rec2020) can have OKLCH chroma values above 0.4, but they cannot be represented in standard 6-digit HEX5. For sRGB-gamut web colors, OKLCH provides the best combination of perceptual accuracy and CSS compatibility available today. Converting from HEX or RGB to OKLCH is the recommended first step before building any new design token system, because starting in a perceptually uniform space avoids the uneven scales you would inherit from HSL.
The learning curve is also much smaller when the whole team shares one scale. Because every shade in an OKLCH palette is computed from L, C, and H, a new designer can read the coordinates and predict the result without a separate reference document. That shared mental model is what makes OKLCH worth adopting even on small projects, where the overhead of training is usually the only argument against it.
OKLCH and the OKLab perceptual model
OKLCH is built on OKLab, a color space Björn Ottosson designed in 2020 to fix specific problems in CIELAB, the 1976 model that underpins LCH6. CIELAB produces visible hue shifts when you adjust lightness for blue hues: a blue at L=50 becomes slightly purple as you increase L to 70. OKLab corrects this by using a different matrix for the XYZ-to-OKLab transformation, which keeps hue constant across lightness changes for all hue angles. OKLCH inherits this correction, making it the first widely adopted polar color space where hue truly stays fixed as you step lightness.
The matrix math behind OKLab
The OKLab conversion from XYZ-D65 involves two matrix multiplications and a cube root. The first matrix transforms XYZ to an opponent-color space (LMS). The second matrix rotates the LMS axes to align with perceptual unique hues. The cube root compresses the dynamic range to match human sensitivity. These operations are fixed: there are no parameters to tune, and every implementation uses the same matrices. The result is a space where Euclidean distance correlates with perceived color difference, which is the property that makes OKLCH useful for palette generation and color matching.
OKLCH for data visualization color scales
Data visualization requires color scales that are perceptually uniform, colorblind-safe, and interpretable. OKLCH addresses all three requirements. A sequential scale (light to dark) steps L from 0.90 to 0.20 while holding H and C constant, producing a smooth gradient where each step looks equidistant. A diverging scale holds C constant and steps L from a dark endpoint through a neutral midpoint to a light endpoint. A qualitative scale holds L and C constant and steps H by equal angles around the hue wheel, producing categories that are equally distinguishable.
Colorblind-safe palette selection in OKLCH
Approximately 8% of men and 0.5% of women have some form of color vision deficiency, most commonly deuteranopia (green weakness) or protanopia (red weakness)7. In OKLCH, colors that differ only in hue angle near the red-green axis (H around 0 to 180) become indistinguishable for deuteranopic viewers. Selecting palette hues that are separated by at least 60 degrees on the blue-yellow axis (H around 180 to 300) ensures distinguishability for all common color vision deficiencies. OKLCH makes this selection process explicit because the hue angle directly corresponds to the perceptual dimension that colorblind viewers struggle with.
Try in the tool
Open the Color Format Converter tool pre-filled to OKLCH to verify it or try a different one.
Check OKLCH in the tool →- 1.
"Oklab color space," Wikipedia, accessed June 2026. https://en.wikipedia.org/wiki/OKLab
- 2.
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
- 3.
"types: <color>: oklch() (OKLCH color model)," caniuse.com, accessed June 2026. https://caniuse.com/mdn-css_types_color_oklch
- 4.
Tailwind CSS, "Colors," tailwindcss.com, accessed June 2026. https://tailwindcss.com/docs/colors
- 5.
W3C, "CSS Color Module Level 4," w3.org, June 2026. https://www.w3.org/TR/css-color-4/
- 6.
W3C CSS Working Group, "[css-color] Add OKLab, OKLCH," github.com, 2022. https://github.com/w3c/csswg-drafts/issues/6642
- 7.
"Color blindness," Wikipedia, accessed June 2026. https://en.wikipedia.org/wiki/Color_blindness
A color space is perceptually uniform when equal numeric distances correspond to roughly equal perceived color differences. In such a space, moving 0.1 units in any direction looks like the same size step to the human eye, regardless of the starting color. OKLCH approximates this property more closely than HSL or RGB.
Approximate hue angles in OKLCH: red is around 30°, orange around 55°, yellow around 110°, green around 145°, cyan around 195°, blue around 260°, and violet-blue around 270°. These differ from HSL hue angles because the perceptual model shifts the boundaries between color families.
No fixed maximum. For colors within the sRGB gamut, chroma values above 0.4 are rare. The sRGB gamut boundary varies by hue and lightness: at L=0.5, some hues max out around C=0.15, while others reach C=0.35. The P3 gamut extends to higher chroma values that cannot be encoded as standard HEX.
OKLab uses Cartesian coordinates L, a, and b to represent the same perceptual space. OKLCH is the polar form of OKLab: C = √(a² + b²) and H = atan2(b, a). The two models are equivalent. Switching between them is a coordinate transformation, not a conversion between color spaces.
No. CapyToolkit runs the entire oklch() conversion locally in your browser using JavaScript. No color values are transmitted to any server, and nothing is stored anywhere.
What Is HSV?
HSV stands for Hue, Saturation, Value. It describes colors in terms a painter would recognize. Hue names the color family, saturation controls how much grey dilutes it, and value determines how close it is to black. Developed alongside HSL in the 1970s for computer graphics, HSV became the dominant format for color picker tools. Photoshop, macOS Color Picker, and most design tool color dialogs use HSV (sometimes labeled HSB, for Hue, Saturation, Brightness) as their primary representation.1
What is HSV?
How HSV differs from HSL
Both HSV and HSL use the same hue angle and the same meaning for saturation zero (achromatic grey). Their third channel is where they diverge structurally. In HSL, lightness 100% always produces white regardless of saturation. In HSV, value 100% with saturation 100% produces the most vivid version of the hue. White requires value 100% and saturation 0% simultaneously. Consequently, HSV handles the vivid-to-dark axis directly (reducing value darkens the hue), while HSL handles the dark-to-light axis (increasing lightness washes out and eventually whitens the hue). Photoshop uses HSV because darkening a color by reducing value is more intuitive for paint-style workflows.2
Where HSV is used in practice
Native OS color pickers on macOS, Windows, and iOS all expose an HSV interface as their primary wheel-plus-slider control, and Adobe Photoshop, Illustrator, and InDesign display color in HSB, which is their term for the same HSV model. This broad tooling support means that learning HSV remains a practical skill even as OKLCH gains adoption for CSS work.
HSV in game engines and image processing
Many JavaScript color picker libraries use HSV internally for their gradient slider implementations because the gradient from vivid to black is easier to render in HSV than in HSL. Image processing libraries like OpenCV perform hue-based color detection and segmentation in HSV space because the saturation and value channels separate color from brightness more cleanly than RGB for thresholding operations.3 HSV also dominates in game engine inspectors, where designers pick colors by wheel rather than by numeric input.
The single coordinate system also makes it easy to script repetitive color work. Because the wheel and the value slider are independent, a tool can sweep value while holding hue fixed to generate shading variants without touching the color family. That independence is why procedural art and sprite generators lean on HSV, since stepping one channel produces a predictable visual change instead of the three-channel drift you get from moving in RGB.
Converting HSV to CSS-compatible formats
CSS does not include an hsv() function. To use an HSV color in a stylesheet, you must first convert it to HSL, RGB, or HEX. The conversion is lossless within floating-point precision. A color defined in HSV maps to exactly one set of CSS-compatible values. The hue angle is identical in HSV and HSL, so the conversion only affects the saturation and value/lightness channels. Saturation in HSV typically produces a higher percentage value than the corresponding HSL saturation for the same color: hsv(217, 76%, 96%) converts to approximately hsl(217, 91%, 60%). CapyToolkit performs this conversion locally in your browser, so you can move from a design tool's HSV readout to a CSS-ready value in a single step.
HSV in computer graphics and game engines
HSV is the dominant color model in real-time graphics because its cylinder geometry maps cleanly to GPU-friendly math. A shader that shifts hue by rotating the H channel, adjusts saturation by scaling S, and modulates brightness by scaling V can run in a single fragment shader pass with three multiply-add operations. Game engines including Unity and Unreal expose HSV (or HSB) as their inspector color format, and many in-engine color pickers use the hue wheel plus saturation-value square that HSV naturally describes. Converting a CSS color to HSV gives you the coordinates to enter directly into a game engine's color property.4
HSV for procedural color generation
Procedural content generation often starts with a base hue and varies saturation and value to create natural-looking color variation. A terrain generator might fix H at 120 (green) and randomize S between 40% and 80% and V between 30% and 70% to produce a range of forest greens. This is simpler in HSV than in RGB because the three perceptual dimensions (color family, intensity, brightness) are separated into independent channels. Converting the generated HSV values back to RGB or HEX for use in a web-based game UI is a single matrix operation.
The relationship between HSV and the Munsell color system
HSV approximates the Munsell color system's cylindrical organization (hue, chroma, value) but with a critical difference: Munsell is perceptually uniform while HSV is not. In Munsell, equal steps in value produce equal perceived brightness differences; in HSV, a value step from 0.5 to 0.6 produces a larger perceived brightness change for a yellow hue than for a blue hue. This non-uniformity means HSV is a convenient computational model but a poor choice for generating perceptually balanced color scales. For any workflow that requires perceptual accuracy, convert HSV to OKLCH and perform the scale generation in OKLCH space.5
Why HSV persists despite its perceptual limitations
HSV persists because it is computationally simple, visually intuitive for single-color selection, and deeply embedded in tooling. Every major design tool, game engine, and OS color picker implements HSV because the hue wheel is the most natural interface for choosing a single color. The perceptual non-uniformity only matters when you are generating multi-step scales or comparing colors across hue families, which is a more specialized use case. For the common task of "pick a color that looks right," HSV's intuitive geometry outweighs its mathematical imperfections.
Try in the tool
Open the Color Format Converter tool pre-filled to HSV to verify it or try a different one.
Check HSV in the tool →- 1.
"HSL and HSV," Wikipedia, accessed June 2026. https://en.wikipedia.org/wiki/HSL_and_HSV
- 2.
Adobe, "Choose colors with the 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.
OpenCV, "Changing Colorspaces," docs.opencv.org, accessed June 2026. https://docs.opencv.org/4.x/df/d9d/tutorial_py_colorspaces.html
- 4.
Unity Technologies, "Select colors and color gradients," docs.unity3d.com, accessed June 2026. https://docs.unity3d.com/Manual/InspectorColorPicker.html
- 5.
"Munsell color system," Wikipedia, accessed June 2026. https://en.wikipedia.org/wiki/Munsell_color_system
Yes. HSB (Hue, Saturation, Brightness) and HSV (Hue, Saturation, Value) are the same model under different names. Photoshop uses HSB; most programming literature and color science texts use HSV. The coordinates and behavior are identical.
White in HSV requires both value 100% and saturation 0%. At saturation 100% and value 100%, the result is the most vivid possible version of the hue: a pure, undiluted color. Reducing saturation at that value level moves the color toward white.
Not directly. CSS defines hsl(), rgb(), hex, and oklch(), but not hsv(). Convert your HSV value to HSL (the hue angle is the same), RGB, or HEX using this tool to get a CSS-compatible form.
In Photoshop's Color Picker, the H field is the hue angle (0–360°), S is saturation (0–100%), and B (Brightness) is the value channel (0–100%). These map directly to HSV H, S, and V. Enter the Photoshop values into an HSV converter to get HEX or RGB.
No. All conversions run locally in your browser. Nothing is sent to any server at any point.
What Are CSS Color Spaces?
A CSS color space defines the range of colors a format can express and the mathematical model that maps numbers to visible colors. Most web colors live in sRGB, the color space defined for standard displays in 1996. Modern screens, particularly smartphones and professional monitors, can display colors outside sRGB. This wider range is called the P3 gamut. CSS Color Level 4 introduces multiple color spaces alongside new syntax to express wide-gamut colors, making it possible to target the full capability of modern displays from CSS.1
What is a CSS color space?
rgb(), and hsl()), Display P3 (approximately 25% more colors than sRGB, used by modern smartphones, tablets, and professional monitors), Rec2020 (a broadcast standard with an even wider gamut), and perceptual spaces including OKLab and OKLCH. Each space maps the same numeric value to a different visible color.1sRGB and the limits of legacy CSS color
sRGB is the color space implicitly used by every legacy CSS color format: HEX, rgb(), hsl(), and hsv(). Defined in 1996 for CRT monitors, sRGB covers about 35% of all visible colors. This persistence is not accidental: every browser, design tool, and OS color picker defaults to sRGB for legacy formats, making it the safest choice for cross-platform compatibility.
Why sRGB persists as the default
Modern displays, particularly P3-capable screens on iPhone, iPad Pro, MacBook Pro, and many Android flagships, can render colors outside sRGB that appear more vivid than anything expressible in #rrggbb. Consequently, a lime green that looks vivid on a P3 screen appears duller on an sRGB display, and a lime expressed in HEX cannot reach the full vivid range that a P3-capable display could show.
The same default also keeps tooling simple, because every parser, exporter, and diff tool can assume sRGB unless told otherwise. That assumption is why legacy HEX pasted into a P3 pipeline still renders sensibly instead of failing, since the older format maps onto the smaller gamut everyone already understands. Treat sRGB as the reliable baseline and reach for P3 only when a specific display target justifies the extra complexity.2
Display P3 and wide-gamut CSS
CSS Color Level 4 exposes the P3 gamut through the color() function: color(display-p3 0.5 1 0 / 1) is a vivid lime that exceeds the sRGB boundary. Browsers on P3 displays render this to the full vivid gamut; browsers on sRGB displays clamp it to the nearest sRGB color. This graceful degradation makes P3 colors safe to use as an enhancement. The fallback on sRGB displays is the closest representable color, not a broken render. Using oklch() to specify colors lets the browser automatically clip to the P3 or sRGB gamut boundary depending on the display, without needing separate fallback declarations.3
Choosing a color space for web projects
For maximum compatibility, sRGB via HEX or rgb() covers every display and tool in production today. For design token systems targeting modern CSS, oklch() provides perceptual uniformity within the sRGB gamut and a clear upgrade path to P3. For apps explicitly targeting high-end displays, such as photography tools, medical imaging, and professional design applications, color(display-p3 …) unlocks the wider gamut. The safe default for most web projects is sRGB, with oklch() used for token definition and HEX used for tool handoffs. Wide-gamut P3 requires intentional adoption and testing on both P3 and sRGB displays to ensure colors look acceptable on both.
Rec2020 and the future of ultra-wide-gamut CSS
Rec2020 is a broadcast color space defined for ultra-high-definition television that covers approximately 76% of the CIE 1931 visible color gamut, compared to P3's 50% and sRGB's 35%.4 CSS Color Level 4 includes Rec2020 as a supported space in the color() function: color(rec2020 0.5 0.8 0.2) specifies a vivid green that exceeds even P3. As display technology improves and Rec2020-capable monitors become more common, CSS will be ready to express these colors. For now, Rec2020 colors in CSS are primarily relevant for video production workflows and HDR content, where the target display is known to support the wider gamut.
HDR color and the hdr() function in CSS Color Level 5
CSS Color Level 5 (currently in draft) introduces the hdr() function for high-dynamic-range colors that exceed the 0 to 1 range of standard color channels.5 An HDR red might be specified as hdr(1.5 0 0) with a channel value above 1.0, representing a brightness that exceeds the display's white point. This is relevant for HDR video content and professional color grading, not for standard web UI design. Understanding the distinction between wide gamut (more saturated colors) and HDR (brighter colors) helps you choose the right CSS function for the display technology you are targeting.
Color space conversion performance in JavaScript
Converting between color spaces in JavaScript is fast for individual colors but can be a bottleneck when processing large datasets. A single sRGB-to-OKLCH conversion involves two 3x3 matrix multiplications, a cube root, and a trigonometric function, totaling roughly 30 floating-point operations. For a single color, this completes in under a microsecond. For a million pixels (a 1000x1000 image), the total time adds up to hundreds of milliseconds on the main thread. When you need to convert large image datasets, use WebGL shaders that perform the matrix math in parallel on the GPU, or offload to a Web Worker to avoid blocking the UI.
TypedArray-based batch conversion
For batch conversion of thousands of colors in JavaScript, use Float32Array to store RGB triplets and perform the conversion with vectorized operations. A Float32Array of length 3N stores N colors as contiguous RGB triplets. The conversion loop reads three floats at a time, applies the matrix, and writes the OKLCH result to a second Float32Array. This approach is 3 to 5 times faster than converting individual colors in a loop with object allocations because it avoids garbage collection pressure and benefits from CPU cache locality. CapyToolkit processes all conversions locally in your browser, and no color data is transmitted to any server.
Try in the tool
What to look for
- Display P3 browser support Chrome 111+, Firefox 113+, Safari 15.0+, Edge 111+
- sRGB coverage all standard HEX, RGB, HSL, HSV, and most OKLCH values
Open the Color Format Converter tool to try this yourself.
Open the tool →- 1.
W3C, "CSS Color Module Level 4," w3.org, June 2026. https://www.w3.org/TR/css-color-4/
- 2.
"sRGB," Wikipedia, accessed June 2026. https://en.wikipedia.org/wiki/SRGB_color_space
- 3.
Mozilla Developer Network, "color() CSS function," developer.mozilla.org, accessed June 2026. https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/color_value/color
- 4.
"Rec. 2020," Wikipedia, accessed June 2026. https://en.wikipedia.org/wiki/Rec._2020
- 5.
W3C, "CSS Color HDR Module Level 1," w3.org, June 2026. https://www.w3.org/TR/css-color-hdr-1/
A color model is a mathematical description of how colors are represented: RGB (three additive channels), HSL (hue, saturation, lightness), or OKLCH (perceptual polar). A color space adds a specific set of reference points and a defined gamut to a model. sRGB is a color space that uses the RGB model with specific red, green, and blue primaries. Display P3 uses the same RGB model with different, wider primaries.
Most Apple devices released after 2017 support Display P3, including all iPhones from 7 onward, iPad Pros, and MacBook Pros. Many Samsung Galaxy and Google Pixel phones also support P3. In CSS, you can detect P3 support with @media (color-gamut: p3) and apply enhanced colors conditionally.
Yes. color(display-p3 r g b) is supported in Chrome 111+, Firefox 113+, Safari 15.0+, and Edge 111+. Safari supported it earlier, making it one of the first browsers to expose wide-gamut CSS color.
The browser maps the out-of-gamut P3 color to the nearest representable sRGB color. This is called gamut mapping or gamut clipping. The result is less vivid than on a P3 display but not broken or invisible. The degradation is graceful: the color family is preserved, only the saturation is reduced.
The tool converts within the sRGB gamut, which covers all standard HEX, RGB, HSL, HSV, and most OKLCH values used in web design. Out-of-gamut P3 colors with OKLCH chroma above the sRGB boundary are clamped to the nearest in-gamut value. Nothing you enter is stored or transmitted.