OKLCH Color Converter
OKLCH is the most editable color format in modern CSS.1
In OKLCH, adjusting the L channel makes a color lighter or darker without shifting its hue. Rotating H changes the hue family without changing perceived brightness. Reducing C moves any color toward grey without touching its lightness. These properties are impossible to achieve directly in HEX or RGB, where every adjustment changes multiple perceptual attributes simultaneously. Converting between OKLCH and legacy formats is the bridge between the perceptual control of modern CSS and the compatibility constraints of older tools.
Opens the Color Format Converter with the value from this section already filled in.
Open in the tool →Understanding OKLCH coordinates
OKLCH stands for the OKLab polar representation developed by Björn Ottosson in 2020 as a perceptually uniform alternative to HSL and CIELAB.1 L is perceptual lightness from 0 (black) to 1 (white). C is chroma, the distance from achromatic grey, starting at 0 with no fixed maximum though most sRGB colors fall below 0.4. H is the hue angle in degrees on a 0 to 360 circle. These three dimensions are independent in perception, so changing L does not shift the perceived hue or colorfulness and the format becomes uniquely useful for generating accessible color scales where each shade step looks equidistant from the adjacent ones.
Converting OKLCH to and from other formats
Converting OKLCH to HEX or RGB routes through OKLab, XYZ-D65, and linear sRGB before gamma correction and integer rounding.2 The reverse path, from HEX or RGB to OKLCH, follows the same pipeline inverted: linearize the sRGB channels, transform to XYZ, transform to OKLab, and extract polar coordinates. The conversion is mathematically exact for sRGB-gamut colors with rounding error only at the final integer step. Colors outside sRGB (high-chroma P3 or Rec2020 values) cannot be fully represented in HEX and require gamut mapping before conversion. Each stage of the pipeline is a well-defined color science transformation, which means any implementer can reproduce the exact same results from a published specification rather than from a closed-source library.
Browser support and practical use
oklch() is a first-class CSS color function in Chrome 111+, Firefox 113+, Safari 15.4+, and Edge 111+.3 CSS custom properties that use oklch() work without any build step or polyfill, so design tokens defined as oklch() drop directly into production stylesheets targeting modern browsers. Furthermore, oklch() integrates with CSS relative color syntax where expressions like color(from oklch(0.612 0.212 261.5) oklch calc(l + 0.1) c h) produce a lighter variant in pure CSS without any JavaScript. Tokens stored in this format are forward-compatible with future CSS color features, whereas tokens stored in HEX require conversion before use in color-mix() or relative color expressions.
Building a color scale by rotating hue in OKLCH
OKLCH hue rotation produces harmonious multi-color palettes because the perceptual lightness stays constant as you move around the hue wheel, and you can derive a lighter shade from an OKLCH base by stepping L while H stays fixed.4 Starting from oklch(0.65 0.20 260) as your primary blue, a complementary accent at oklch(0.65 0.20 80) gives you a yellow-green at the same perceived brightness. A triadic palette adds oklch(0.65 0.20 140) and oklch(0.65 0.20 380, which wraps to 20). Each of these colors looks equally vivid and equally bright, which is impossible to achieve by rotating hue in HSL.
Adjusting chroma for visual hierarchy
Not every color in a palette needs the same chroma. Reserve high chroma (C above 0.15) for interactive elements and primary actions that need to draw attention. Use lower chroma (C between 0.05 and 0.10) for secondary text, borders, and background tints. Keeping L constant while varying C creates a natural visual hierarchy: high-chroma elements stand out against low-chroma surroundings without any change in perceived brightness. This approach works especially well for data visualization, where you need distinguishable categories that do not imply a brightness ordering.
The same principle applies to disabled states, where dropping C toward zero while holding L reproduces the muted look browsers apply to inactive controls. Because the lightness stays put, the disabled element reads as the same color merely dimmed, rather than as a different hue altogether. Keeping the change in the chroma channel is what makes the hierarchy feel intentional instead of accidental, and it keeps the relationship to the active color explicit at a glance.
OKLCH and CSS color-mix() for dynamic tints and shades
CSS color-mix() blends two colors in a specified color space, and OKLCH produces the most perceptually uniform results. The expression color-mix(in oklch, oklch(0.612 0.212 261.5) 70%, white) creates a 70/30 blend of your blue and white in perceptual space, producing a lighter tint that preserves the original hue without the pinkish shift you get from blending in sRGB. Similarly, color-mix(in oklch, oklch(0.612 0.212 261.5) 80%, black) produces a darker shade that stays in the same hue family.
Why blending in OKLCH beats blending in sRGB
Blending a saturated blue with white in sRGB shifts the result toward pink because the gamma curve distorts the midpoint between the two colors. OKLCH avoids this by performing the blend in a linear perceptual space where the midpoint between blue and white is a desaturated blue, not a purple-pink.5 For any workflow that generates tints and shades programmatically (design token pipelines, theme generators, component libraries), specifying in oklch as the color-mix() color space produces output that matches human expectations.
OKLCH for accessible color system design
Accessibility starts with lightness discipline. In OKLCH, the L channel directly controls perceived brightness, which means you can guarantee WCAG contrast ratios by controlling the L difference between foreground and background colors. A text color at L=0.25 on a background at L=0.95 produces a contrast ratio above 10:1, well exceeding AAA.6 The same L difference in HSL does not guarantee the same perceived contrast because HSL lightness is not perceptually uniform.
Defining minimum L-difference tokens
Define your design tokens with explicit L-difference rules: interactive text must sit at least 0.4 L units away from its background, and large text must sit at least 0.25 L units away. These rules are easy to verify in OKLCH because the L channel is a single number. In HSL or RGB, the same check requires computing relative luminance from all three channels. Building your color system in OKLCH from the start makes accessibility a structural property of the token set rather than an afterthought checked by an external tool.
When to use this
Use this when working with CSS Color Level 4 oklch() values and you need to convert to or from HEX, RGB, or HSL, particularly when you are building a design token system that targets perceptual uniformity across every shade in the palette.
Examples
Brand HEX → OKLCH for CSS custom property
#c8ff00
oklch(0.960 0.241 128.2)
Set --color-brand: oklch(0.960 0.241 128.2) in :root.
OKLCH → HEX for Figma and email fallbacks
oklch(0.612 0.212 261.5)
#3b82f6
Use the HEX value in any tool that doesn't accept oklch() yet.
- 1.
"Oklab color space," Wikipedia, en.wikipedia.org, accessed June 2026. https://en.wikipedia.org/wiki/Oklab_color_space
- 2.
W3C, "CSS Color Module Level 4," w3.org, accessed June 2026. https://www.w3.org/TR/css-color-4/
- 3.
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
- 4.
Jakub Krehl, "OKLCH Skill," github.com, accessed June 2026. https://github.com/jakubkrehel/oklch-skill
- 5.
Mozilla Developer Network, "color-mix() CSS function," developer.mozilla.org, accessed June 2026. https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/color_value/color-mix
- 6.
W3C, "Relative Luminance Definition," w3.org, accessed June 2026. https://www.w3.org/TR/WCAG21/relative-luminance.html
Convert HEX to OKLCH
HEX is the most portable color format. OKLCH is the most editable.
HEX encodes red, green, and blue channel intensities, which makes the numbers compact for storage, but gives no intuitive signal about how the color will look after adjustment. OKLCH separates perceptual lightness, chroma (colorfulness), and hue angle in a space where equal numeric steps produce roughly equal perceived differences. Converting a HEX brand color to OKLCH gives you coordinates you can adjust by feel rather than by trial and error across three opaque channel values.
Opens the Color Format Converter with the value from this section already filled in.
Open in the tool →How HEX to OKLCH conversion works
Converting HEX to OKLCH routes through four intermediate color spaces. First, HEX decoding produces linear sRGB by undoing the gamma curve. Second, a matrix multiplication produces XYZ-D65, a device-independent space. Third, a non-linear transform produces OKLab, Björn Ottosson's perceptual model. Fourth, a polar-coordinate extraction produces OKLCH from OKLab.1 The lightness L is the OKLab L channel (0–1 range). Chroma C is the Euclidean distance from the OKLab origin: √(a² + b²). Hue H is the angle in degrees: atan2(b, a). Consequently, the hue angle in OKLCH is not the same as the hue angle in HSL or HSV; it is measured in a perceptually uniform space rather than the raw RGB model.
Where HEX to OKLCH conversion comes up
CSS Color Level 4 includes oklch() as a first-class color function supported in all modern browsers. Tailwind CSS v4 defines its built-in palette entirely in OKLCH, meaning design systems built on Tailwind v4 often need to express custom brand colors in that space.2 Converting to OKLCH is the recommended first step before building a color scale: holding L and C constant while rotating H produces a harmonious palette of related colors, whereas the same operation in HSL produces visible lightness jumps at certain hue angles because HSL is not perceptually uniform. Figma does not yet accept OKLCH coordinates natively in fill inputs, so converting back to HEX for handoff is still a common workflow.
HEX to OKLCH edge cases and rounding
Very dark colors (L near 0) and very light colors (L near 1) produce low chroma values near 0 because the perceptual color space compresses the sRGB gamut near the white and black points. Colors outside the sRGB gamut (P3 or Adobe RGB colors) may show high-chroma or out-of-range L values in OKLCH.3 For standard web colors, all HEX values within the sRGB gamut convert without clamping. Floating-point arithmetic means a round-trip conversion may shift the last RGB channel digit by 1. Rounding differences between this converter and a CSS preprocessor plugin are typically within 1 unit per channel, which is below the threshold of visual perception.
The HEX to OKLCH pipeline in detail
Converting HEX to OKLCH passes through four color spaces, each with a specific role. First, the HEX string decodes to three 0 to 255 integers, which normalize to 0 to 1 floats. Second, the sRGB transfer function (gamma curve) linearizes these floats: values at or below 0.04045 divide by 12.92, and values above it apply the power curve with the 0.0031308 breakpoint.4 Third, a 3x3 matrix multiplication transforms linear sRGB to XYZ-D65, a device-independent space anchored to a standard illuminant. Fourth, a non-linear matrix converts XYZ-D65 to OKLab, and the final step extracts polar coordinates (L, C, H) from the Cartesian OKLab values. Every step is a fixed mathematical operation with no approximation.
Why the gamma curve matters for accuracy
Skipping the gamma linearization step is the most common error in hand-rolled color conversion code. The sRGB gamma curve means that the HEX value #808080 (mid-grey) does not represent 50% light intensity; it represents roughly 21% linear light.4 Converting #808080 to OKLCH without undoing the gamma gives you L near 0.5, which is wrong. The correct L for mid-grey is approximately 0.53. Always apply the full sRGB-to-linear step before the matrix transformations, or your OKLCH values will be systematically biased toward higher lightness for dark colors and lower lightness for bright colors.
The bias is subtle enough that it passes a casual visual check, which is exactly why it survives in so much hand-written code. A developer who ships a half-correct converter may not notice that their dark brand colors render slightly washed out until they compare against a reference value side by side. Running the full sRGB-to-linear step removes the discrepancy entirely, so the OKLCH output matches what CSS itself computes internally when it parses a HEX value.
Choosing OKLCH coordinates for design tokens
When you express a HEX brand color in OKLCH for use as a design token, the resulting coordinates tell you how the color behaves in perceptual space. The L value shows where it sits on the lightness scale: L=0.96 (like #c8ff00) is very light, suitable for backgrounds or highlights; L=0.61 (like #3b82f6) is mid-range, suitable for primary interactive elements. The C value shows how saturated it is: C=0.24 is vivid, C=0.05 is muted. Note that CSS treats 100% as 0.4 for the C component, so most in-gamut sRGB colors stay well under that ceiling.5 The H value shows the hue family, which you can use to find complementary or analogous colors by adding or subtracting hue angles.
Storing the canonical value in OKLCH
Store your design tokens in OKLCH and derive HEX, RGB, or HSL at build time for tools that need those formats. This keeps the authoritative value in the most perceptually meaningful space. A token defined as oklch(0.612 0.212 261.5) can produce #3b82f6 for Figma, rgb(59, 130, 246) for canvas, or hsl(217, 91%, 60%) for legacy CSS, all from the same source. If you store the canonical value in HEX and convert to OKLCH on read, you lose the perceptual precision that makes OKLCH useful in the first place.
OKLCH for programmatic color scale generation
Generating a color scale from a single HEX input is a common design system task. Convert the HEX to OKLCH first, then create variants by adjusting L while holding H and C approximately constant. A 10-step scale from 50 to 950 needs L values that are perceptually equidistant: the steps are not linearly spaced in L because human vision is more sensitive to lightness differences in the mid-range than at the extremes. Tailwind v4's built-in palette uses a carefully tuned L curve that compresses steps near the light and dark ends.
Adjusting chroma across lightness steps
Holding C constant across all lightness steps produces colors that look oversaturated at very light and very dark extremes. Reduce C by 20 to 30% for steps above L=0.85 and below L=0.30 to match the natural chroma compression of the sRGB gamut at those lightness levels. This adjustment produces a scale where every step looks like a natural shade of the same hue family rather than an artificially vivid outlier at the extremes. The exact C reduction curve depends on the hue: yellows tolerate higher chroma at light lightnesses than blues do.
When to use this
Use this when a brand color stored as HEX needs to be expressed in OKLCH for a Tailwind v4 config, a CSS Color Level 4 stylesheet, or a design system that uses perceptual lightness coordinates for color scale generation.
Examples
Brand HEX → Tailwind v4 custom color
#c8ff00
oklch(0.960 0.241 128.2)
Set in @theme: --color-brand: oklch(0.960 0.241 128.2);
Primary blue → CSS Color Level 4 variable
#3b82f6
oklch(0.612 0.212 261.5)
Use: --color-primary: oklch(0.612 0.212 261.5);
- 1.
Björn Ottosson, "A perceptual color space for image processing," bottosson.github.io, accessed June 2026. https://bottosson.github.io/posts/oklab/
- 2.
Adam Wathan, "Tailwind CSS v4.0," tailwindcss.com, January 2025. https://tailwindcss.com/blog/tailwindcss-v4
- 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.
World Wide Web Consortium, "CSS Color Module Level 4," W3C Candidate Recommendation Draft, September 2026. https://www.w3.org/TR/css-color-4/
- 5.
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
L is perceptual lightness, ranging from 0 (black) to 1 (white). C is chroma, which measures how colorful the color is, starting at 0 (grey) with no fixed maximum; typical sRGB colors fall below 0.4. H is the hue angle in degrees, 0–360, where 30° is red-orange, 145° is green, and 270° is violet-blue.
HSL lightness steps produce unequal perceived brightness: yellows look brighter than blues at the same L value. In OKLCH, equal L steps produce roughly equal perceived lightness jumps across all hues. This makes OKLCH the reliable choice for generating accessible, visually consistent shade ramps.
Yes, as of 2023. Chrome, Firefox, Safari, and Edge all support oklch() natively in CSS. No polyfill is needed for modern browsers. Internet Explorer does not support it.
The tool converts HEX to OKLCH using the sRGB-to-OKLCH pipeline. HEX codes by definition sit within the sRGB gamut. Wide-gamut P3 or Rec2020 colors outside sRGB cannot be represented as standard 6-digit HEX without clamping.
No. All conversions run entirely in your browser. Nothing is uploaded to any server at any point.
Convert OKLCH to HEX
OKLCH gives perceptual control. HEX gives universal compatibility.
OKLCH is increasingly used in design systems and Tailwind v4 configurations to generate color palettes that are visually consistent across hue angles. Most color fields outside a browser stylesheet (Figma fill inputs, SVG color attributes, email HTML, design documentation) still accept only HEX or RGB. Converting OKLCH values to HEX bridges the gap between modern perceptual color design and the broad ecosystem of tools that have not yet adopted CSS Color Level 4 syntax.
Opens the Color Format Converter with the value from this section already filled in.
Open in the tool →How OKLCH to HEX conversion works
Converting OKLCH to HEX follows the reverse of the HEX-to-OKLCH pipeline. First, the OKLCH coordinates produce OKLab Cartesian values by computing a as C times cos(H in radians) and b as C times sin(H in radians). Second, OKLab converts to XYZ-D65 through a linear matrix multiplication. Third, another matrix multiplication transforms XYZ-D65 to linear sRGB. Fourth, the sRGB transfer function applies gamma correction to produce 0 to 255 integers, which the encoder then writes as two-digit hex pairs.1 The conversion is deterministic and reversible for any color within the sRGB gamut. Colors outside sRGB must be clamped to the gamut boundary before the final hex encoding step. Achromatic colors with chroma near 0 convert cleanly because the hue angle contributes nothing when C is zero.
Where OKLCH to HEX conversion comes up
Tailwind v4 and CSS Color Level 4 design workflows generate palette values in OKLCH. When those values need to populate Figma styles, Storybook color tokens, or a style guide PDF, HEX is the expected format. Email HTML (which must support clients like Outlook that do not parse oklch()) requires fallback HEX values for every perceptual color. Any CI pipeline that validates color contrast ratios using tools expecting HEX or RGB input needs the OKLCH values converted to HEX before the accessibility check runs. Design documentation tools such as Zeroheight and Supernova accept only HEX in their color swatch fields, so a conversion step is required before pasting OKLCH tokens into component specifications.
OKLCH to HEX edge cases and rounding
OKLCH values with L above 1 or below 0 are out-of-range and should be clamped before conversion. Chroma values above the sRGB gamut boundary for a given hue and lightness produce RGB channels above 255 or below 0 after conversion; the tool clamps these to the 0–255 range, which may shift the perceived hue or lightness slightly.1For any oklch() value originally derived from a standard HEX color, the round-trip produces the original HEX, differing by at most 1 in one channel due to floating-point rounding in the intermediate OKLab step. The same rounding behavior applies to RGB and HSL round-trips: a shift of 1 unit in one channel is the normal floating-point tolerance and is not a sign of a conversion error.
When you need HEX fallbacks for older browsers
Providing a HEX fallback before an oklch() declaration is the standard pattern for supporting browsers that do not yet parse oklch(), and you can get a HEX fallback for every oklch() value in the converter. Write the declaration as two lines: --color-brand: #3b82f6; --color-brand: oklch(0.612 0.212 261.5);. Browsers that do not understand oklch() ignore the second line and use the HEX value. Modern browsers parse both and apply the oklch() value because it comes last. This pattern works without any JavaScript or build step, making it the simplest progressive enhancement strategy for OKLCH adoption.
Automating fallbacks with PostCSS
The postcss-oklch plugin automates HEX fallback insertion at build time. After Tailwind v4 generates CSS with oklch() values, PostCSS processes the output and inserts a HEX fallback before each oklch() declaration.2 Configure it in postcss.config.js with require("postcss-oklch")() in your plugin list. The plugin reads the oklch() value, converts it to the nearest HEX, and writes the fallback line. This approach keeps your source CSS clean while ensuring every oklch() declaration ships with a compatible fallback in the production build.
The same plugin also normalizes the source oklch() values, so a token written with extra decimal places keeps a consistent fallback across the stylesheet. That consistency matters when the build runs twice on different machines, because a fixed HEX fallback removes any chance of the two runs disagreeing on the legacy color. Treating the PostCSS step as part of the build rather than a manual paste also means the fallback can never drift out of sync with the oklch() value it sits beneath.
OKLCH to HEX for email HTML and SVG compatibility
Email HTML is the most format-constrained environment in front-end development. Outlook (the desktop Windows version) renders email using the Microsoft Word HTML engine, which does not support oklch(), color-mix(), or CSS custom properties. Every color in an email template must be expressed as a 6-digit HEX code in a style attribute or a td bgcolor attribute.3 Converting your OKLCH design tokens to HEX before writing email templates is a mandatory step, not an optional optimization.
SVG fill and stroke attributes
SVG fill and stroke attributes accept HEX and rgb() but not oklch() in most SVG rendering contexts. When you generate SVG icons or illustrations programmatically from a design token system that stores colors in OKLCH, convert to HEX before writing the SVG markup. The conversion is lossless for sRGB-gamut colors, so the SVG rendering matches the browser rendering of the same token. For inline SVG within an HTML document, you can use oklch() in a <style> block that targets SVG elements, since the HTML parser handles the CSS. Standalone .svg files served from a CDN need HEX.
Gamut checking before converting OKLCH to HEX
Not every OKLCH coordinate converts cleanly to HEX. Colors with chroma values above the sRGB gamut boundary for their hue and lightness produce RGB channels outside the 0 to 255 range after conversion. The tool clamps these to 0 or 255, which shifts the resulting color. Before converting an OKLCH value to HEX for production use, check whether the chroma is within the sRGB gamut at that lightness level. At L=0.5, most hues max out around C=0.15 in sRGB; at L=0.8, the maximum drops to roughly C=0.08.4
Using the W3C gamut mapping algorithm
The W3C specification defines a gamut mapping algorithm that reduces chroma in OKLCH space until the color falls within the target gamut. This produces a perceptually close in-gamut color rather than a channel-clamped color with a shifted hue.5 CSS Color Level 4 references this algorithm for the gamut-mapping media feature. When you need to convert a wide-gamut OKLCH value to HEX, reducing chroma by 0.01 increments until all RGB channels fall within 0 to 255 produces a better result than clamping alone.
When to use this
Use this when an OKLCH value from a Tailwind v4 config, a CSS Color Level 4 palette, or an OKLCH design tool needs to be expressed as HEX for Figma, email HTML, SVG, or any system that does not yet accept oklch() natively.
Examples
Tailwind v4 palette value → Figma fill
oklch(0.960 0.241 128.2)
#c8ff00
Paste the HEX directly into Figma's color fill field.
OKLCH scale step → email HTML fallback
oklch(0.612 0.212 261.5)
#3b82f6
Use as the color attribute in email HTML for Outlook compatibility.
- 1.
Björn Ottosson, "A perceptual color space for image processing," bottosson.github.io, accessed June 2026. https://bottosson.github.io/posts/oklab/
- 2.
Jonathan Neal, "@csstools/postcss-oklab-function," npm, accessed June 2026. https://www.npmjs.com/package/@csstools/postcss-oklab-function
- 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.
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.
World Wide Web Consortium, "CSS Color Module Level 4," W3C Candidate Recommendation Draft, September 2026. https://www.w3.org/TR/css-color-4/
The pipeline passes through four floating-point intermediate spaces, each accumulating a tiny rounding error. A round-trip of HEX to OKLCH to HEX typically differs by at most 1 in one RGB channel digit, below the threshold of visual perception but measurable if you compare the integers directly.
Colors with high chroma values at extreme lightness levels may fall outside sRGB. The tool clamps out-of-range RGB channels to 0–255 before encoding to HEX. The result is the closest in-gamut color, which may differ from the original in perceived saturation.
Yes. Tailwind v4 accepts any CSS color syntax in its configuration, including oklch(). This converter is useful for the reverse: when you have OKLCH palette values in your Tailwind config and need the HEX equivalents for documentation or tools that do not support oklch().
In modern browsers (Chrome 111+, Firefox 113+, Safari 15.4+, and Edge 111+, all released in 2023 or later), no polyfill is needed. For Internet Explorer or legacy mobile browsers, a PostCSS plugin like postcss-oklch can convert oklch() to hex or rgb() at build time.
No. CapyToolkit runs all conversions locally in your browser. Nothing is transmitted to any server.
Convert RGB to OKLCH
RGB encodes light intensity. OKLCH encodes perception.
The three RGB channels map directly to the red, green, and blue phosphors of a display, which makes them useful for hardware but opaque for design decisions. OKLCH represents the same three colors as a lightness value (how bright each color looks), a chroma value (how colorful it is), and a hue angle (which color family it belongs to). Converting from RGB to OKLCH transforms a machine-centric encoding into one optimized for designers making perceptual adjustments.
Opens the Color Format Converter with the value from this section already filled in.
Open in the tool →How RGB to OKLCH conversion works
The RGB-to-OKLCH pipeline runs through three intermediate spaces. First, sRGB integers normalize to 0–1 floats and linearize by undoing the sRGB gamma curve. Then a matrix multiplication transforms the linear sRGB triplet to XYZ-D65, a device-independent color space. A second matrix converts XYZ-D65 to OKLab, the perceptual model underlying OKLCH. Finally, OKLCH extracts L directly from the OKLab L channel, computes chroma as √(a² + b²), and hue as atan2(b, a) in degrees.1 The entire pipeline is a fixed sequence of linear algebra: no table lookups, no approximations, and no heuristic shortcuts. Every matrix coefficient is defined by the sRGB specification and the OKLab publication.
Where RGB to OKLCH conversion comes up
RGB-to-OKLCH conversion appears at the intersection of existing tools and modern CSS. A developer who reads a color from a canvas getImageData() call, a computed CSS style, or a database row stored as rgb() integers needs to express it in OKLCH before using it in a Tailwind v4 config. Accessibility tools that compute WCAG contrast ratios in OKLCH space also require the input colors in that format, even when the original design stored them as RGB. Converting first means your contrast checks run against the same perceptual coordinates that the final stylesheet will ship. Design tokens stored as OKLCH survive a change of target format without losing their intended appearance.
RGB to OKLCH edge cases and rounding
RGB integers at the extremes (rgb(0, 0, 0) and rgb(255, 255, 255)) convert cleanly to oklch(0, 0, 0) and oklch(1, 0, 0) respectively. Achromatic values where r equals g equals b produce chroma 0 and an undefined hue, which the conversion outputs as 0° by convention. Very saturated sRGB colors near the gamut boundary may produce OKLCH chroma values above 0.4, which are still within the sRGB gamut but near its edge. Floating-point arithmetic across the four-space pipeline means a round-trip of RGB to OKLCH to RGB may differ by 1 in one channel due to accumulated rounding. This tolerance is within the threshold of visual indifference, so a one-unit shift does not indicate a conversion defect.
Using OKLCH values in CSS custom properties
CSS custom properties that store OKLCH coordinates give you direct access to perceptual channels from any rule in your stylesheet. Define --color-primary: oklch(0.612 0.212 261.5) in :root, then reference it anywhere with var(--color-primary). When you need a lighter variant for a hover state, use CSS relative color syntax: color(from var(--color-primary) oklch calc(l + 0.12) c h).2 In the resolved relative form the origin color is first converted to OKLCh, and its channels are exposed to the calculation as numbers: l between 0 and 1, c between 0 and 0.4, and h between 0 and 360.3 This produces a 12% lighter shade in pure CSS, without a second custom property or a preprocessor loop.
Deriving palette steps with relative color syntax
CSS Color Level 4 relative color syntax lets you derive multiple shades from a single OKLCH base without defining each one manually. Starting from --color-blue: oklch(0.612 0.212 261.5), you can express --color-blue-300 as color(from var(--color-blue) oklch calc(l + 0.22) calc(c * 0.7) h) and --color-blue-700 as color(from var(--color-blue) oklch calc(l - 0.15) calc(c * 0.9) h). Each derived value stays in OKLCH, preserving perceptual uniformity across the full shade range. Browsers that do not support relative color syntax ignore these declarations, so always provide a static fallback value before the derived one.
The relative syntax also keeps every shade bound to the same source token, so a later change to the base color propagates through the entire scale automatically. That single-source behavior is what makes OKLCH scales easier to maintain than hand-listed HSL steps, where each value is an isolated triple that has to be edited on its own. Because the derivation happens in CSS at parse time, the perceptual relationship between steps is preserved even after you swap the base for a different hue.
RGB to OKLCH for canvas and image data workflows
Canvas getImageData() returns raw pixel values as Uint8ClampedArray segments in RGBA order. When you sample a pixel from a canvas, you can read a pixel color as an OKLCH token for a design token or CSS custom property, and the RGB-to-OKLCH conversion is the bridge between the rendering layer and the design system layer.4 A pixel reading [59, 130, 246, 255] converts to approximately oklch(0.612 0.212 261.5), which you can then use in a stylesheet or store as a design token.
Handling alpha channels through the conversion
The OKLCH model does not encode alpha. When you convert an RGBA pixel to OKLCH, the alpha channel passes through unchanged as a separate value. Store it alongside the OKLCH coordinates as a two-part token: oklch(0.612 0.212 261.5 / 0.8) combines the color and alpha in a single CSS expression. For image processing pipelines that need to composite or blend colors, keep alpha as a separate float between 0 and 1 until the final CSS output stage.
Performance considerations for client-side conversion
Converting every pixel in a large image from RGB to OKLCH on the main thread blocks the UI. A 1920x1080 image contains over two million pixels; converting each through the four-space pipeline (sRGB to linear to XYZ to OKLab to OKLCH) takes measurable time on the main thread. Offload bulk conversions to a Web Worker, since a worker runs its script on a background thread without interfering with the user interface, or use WebGL shaders that perform the matrix math in parallel on the GPU.5 For single-color conversions, the synchronous approach is fast enough: a single RGB-to-OKLCH conversion completes in under a millisecond on any modern device.
Caching converted values in a Map
When your application repeatedly converts the same RGB values (for example, reading palette colors from a fixed set of image regions), cache the results in a Map keyed by the RGB string. A lookup like cache.get("59,130,246") avoids re-running the full pipeline for values you have already converted. This pattern is especially useful in real-time applications like video frame analysis or interactive color pickers where the same dominant colors appear across consecutive frames.
When to use this
Use this when a color stored as RGB integers needs to be expressed in OKLCH for a CSS Color Level 4 variable, a Tailwind v4 theme config, or a perceptual color scale calculation.
Examples
Canvas pixel color → OKLCH design token
rgb(200, 255, 0)
oklch(0.960 0.241 128.2)
Use the OKLCH value to generate lighter or darker variants by adjusting L.
DevTools rgb() → CSS custom property
rgb(59, 130, 246)
oklch(0.612 0.212 261.5)
Set --color-primary: oklch(0.612 0.212 261.5) in your :root block.
- 1.
Björn Ottosson, "A perceptual color space for image processing," bottosson.github.io, accessed June 2026. https://bottosson.github.io/posts/oklab/
- 2.
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
- 3.
World Wide Web Consortium, "CSS Color Module Level 4," W3C Candidate Recommendation Draft, September 2026. https://www.w3.org/TR/css-color-4/
- 4.
MDN Web Docs, "CanvasRenderingContext2D.getImageData()," developer.mozilla.org, accessed June 2026. https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/getImageData
- 5.
Mozilla Developer Network, "Using Web Workers," developer.mozilla.org, accessed September 2026. https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers
Both use lightness, chroma, and hue coordinates, but OKLCH uses the OKLab perceptual model, which Björn Ottosson designed in 2020 specifically to fix lightness uniformity issues in the older CIELAB/LCH model. OKLCH produces more visually consistent results when adjusting hue while holding lightness constant.
Yes. Chrome, Firefox, Safari, and Edge all support oklch() natively as of 2023. No polyfill or build step is required for modern browsers.
Yes. Convert the base color to OKLCH to get its L, C, and H coordinates. Then create variants by holding H constant and stepping L from near 0 to near 1. Each step produces a shade that looks perceptually equidistant from adjacent steps, a property that HSL does not guarantee.
Chroma 0 means the color is achromatic: a pure grey with no hue. As chroma increases, the color becomes more vivid. In the sRGB gamut, chroma above 0.4 is unusual; most web colors fall between 0.05 and 0.35 for saturated hues.
No. All conversions run locally in your browser using JavaScript. Nothing is uploaded to any server at any point.