# From HEX to OKLCH: accessible palettes and WCAG 2.1 contrast

> Online color picker free: bidirectional HEX/RGB/HSL/OKLCH/Lab conversions and WCAG 2.1 contrast checker (AA/AAA). OKLCH accessible palette generator.

Free in-browser tool (no upload): https://www.mauriziofonte.it/tools/color-picker-converter

Convert between **HEX, RGB, HSL, OKLCH, Lab** bidirectionally, generate *perceptually uniform* palettes via OKLCH, check the contrast ratio against **WCAG 2.1 AA/AAA**. Built for designers who care about accessibility: combining OKLCH for perceptual consistency and WCAG for real accessibility produces robust palettes on the first pass.

## How to use the color picker

1. **Pick a color** - Click the native color picker to open the system selector, or paste a value into any field (HEX, RGB, HSL, OKLCH, Lab). The five fields are **bidirectional**: change one, the other four update.
2. **Check WCAG contrast** - The contrast checker section shows the ratio of the color against white or black, and the PASS/FAIL for the four WCAG 2.1 levels: normal text AA (4.5:1), normal text AAA (7:1), large text AA (3:1), large text AAA (4.5:1).
3. **Generate the palette** - The OKLCH palette generates 9 lightness stops of the base color while keeping C (chroma) and H (hue) constant. Result: a set of perceptually-uniform harmonic shades, useful for design systems. Click any swatch to set it as the new main color.
4. **Copy the value** - Click the copy button next to each field to push the CSS-ready value to your clipboard. The emitted formats are CSS Color Module Level 4 compatible (oklch(), lab() supported by all modern browsers since 2023).

## Why this color picker

Three things separate this tool from the generic color pickers on SERP.

**OKLCH first-class.** OKLCH (Oklab Lightness Chroma Hue) is the *perceptually uniform* color space defined by Bjorn Ottosson in 2020 and standardized in CSS Color Level 4. It means numerical L (lightness) differences correspond to perceptually uniform differences as seen by the human eye. Practical comparison: two HSL colors with the same S and L but different H can look very different in brightness (HSL light yellow vs HSL same-L blue look much darker). In OKLCH, two colors with the same L look equally bright regardless of hue. That makes OKLCH the ideal tool for generating accessible palettes: same C and H + L variations gives you coherent shades.

**Built-in WCAG 2.1 contrast checker.** WCAG 2.1 accessibility guidelines require a minimum 4.5:1 ratio for normal text (AA) and 7:1 for AAA. The calculation follows the official formula: relative luminance of linearized sRGB, ratio (L1+0.05)/(L2+0.05) with L1 brighter. Implemented here with the standard constants (0.2126/0.7152/0.0722). Auto check against black (#000) and white (#FFF) as foreground. When testing brand palettes, OKLCH-derived stops typically pass first-shot thanks to the perceptually-uniform spacing.

**Fully, CSS Level 4 formats.** No fetches to a color-table server. All the conversions are closed-form standard formulas (sRGB-XYZ matrices, CIE 1976, Ottosson 2020) implemented in JavaScript. Output in canonical CSS format: `oklch(50.86% 0.1545 245.8)`, `lab(40.13 -8.86 -49.05)`, paste-ready into modern stylesheets.

## Glossary

- **sRGB**: Standard color space of the web defined in IEC 61966-2-1 (1999). Gamut: ~35% of visible colors. Default for every consumer monitor up to 2018.
- **OKLCH**: Polar color space (Lightness, Chroma, Hue) based on OKLab. Bjorn Ottosson, 2020. Standardized in CSS Color Level 4. Perceptually uniform.
- **CIE Lab 1976**: L*a*b* color space from the Commission Internationale de l'Eclairage. Historic attempt at perceptual uniformity, but with known errors at high chroma (blue, purple). Useful for backward compatibility, OKLCH is superior.
- **WCAG contrast ratio**: Formula (L1+0.05)/(L2+0.05) with L1, L2 sRGB relative luminance. Range 1:1 (identical) to 21:1 (black on white). WCAG 2.1 thresholds: 3:1 large AA, 4.5:1 normal AA, 7:1 normal AAA.
- **Gamut**: The set of colors representable in a color space. sRGB ~35% of visible, Display P3 ~45%, Rec.2020 ~75%. OKLCH is gamut-agnostic: it represents any color if the display can show it.
- **Hue stability**: Property of a color space: changing L preserves the perceived hue. HSL has no hue stability (light blue shifts toward purple). OKLCH does.

## Frequently asked questions

### Can I paste CSS-formatted colors directly?

Yes. The parsers are permissive: `#0065c0`, `0065c0`, `rgb(0, 101, 192)`, `0 101 192`, `hsl(207, 100%, 38%)`, `oklch(50.86% 0.1545 245.8)`, `lab(40.13 -8.86 -49.05)` are all recognized. Commas, percent signs, spaces are optional as separators.

### Why do two different formats give me visually the same color?

Because the formats are lossless to each other for in-gamut sRGB colors. HEX  RGB  HSL are mathematical identities (sRGB is the base). OKLCH  Lab  XYZ  sRGB have exact roundtrip conversions (modulo last-digit rounding). Lab is computed on the D50 white, the same as the CSS lab() function: the copied value pastes into a stylesheet and renders the same color. The small differences left come from rounding to 8 bits per channel.

### AAA contrast is too strict for my brand colors, can I ignore it?

AAA is mandatory only for public services (government, healthcare) in some countries. For most commercial sites, AA (4.5:1 normal, 3:1 large) is the accepted standard (EU Directive 2102, WCAG 2.1 AA target). If your brand colors fail AA, you can: 1) use them only as decorative accents, never as primary text, 2) tweak the palette by widening L delta, 3) use different colors for text (a derived "text" palette).

### Why use OKLCH instead of classic HSL?

Three reasons. 1) Perceptual uniformity: in OKLCH two shades with the same L look equally bright, in HSL they do not (yellow at L=50 looks brighter than blue at L=50). 2) Hue stability: changing L in HSL shifts the perceived hue, in OKLCH it does not. 3) Wide gamut: OKLCH can represent P3 and Rec.2020 colors natively, HSL is locked to sRGB.

### Can OKLCH/Lab values render outside the sRGB gamut?

Yes. If OKLCH(70% 0.4 250) ends up outside the sRGB gamut, the converter clamps the resulting RGB to [0, 255], producing a "closest" sRGB color but not identical. To see when this happens: compare the OKLCH value you typed with the OKLCH value computed back from the clipped RGB. Significant differences = clipping. For standard web use it is not a problem, RGB stays in-gamut anyway.

### Does it work offline?

Yes. All conversions are closed-form mathematical formulas implemented in JavaScript, no server fetches. Once the page is loaded, you do not need the network anymore.

### Is there an API to integrate the conversions into a script or plugin?

Not as an HTTP endpoint. For scripting: all the formulas are public (sRGB IEC 61966-2-1, CIE 1976, Ottosson 2020) and implementable in any language. For JavaScript: the `color_picker-gui.js` file in this tool is a reusable source-of-truth. In Python: `colour-science`. In Node: `color-js`.

### Is WCAG 3 (APCA) planned?

Not in V1. APCA (Accessible Perceptual Contrast Algorithm) is the new metric proposed for WCAG 3 but still in draft (not ratified as of 2026). When WCAG 3 becomes a W3C Recommendation I will add APCA as a supplementary check. For now WCAG 2.1 is the legally binding standard (EU Directive 2102, US ADA Section 508).

---
Tool by Maurizio Fonte, senior backend engineer. All tools: https://www.mauriziofonte.it/tools/
