# OKLCH no CSS: cores e paletas que fazem sentido

> OKLCH é uma forma de descrever cores por luz (L), croma (C, a intensidade) e matiz (H, o ângulo no círculo de cores), num espaço que acompanha a percepção do olho. No CSS, oklch(62% 0.19 260) é um azul. A vantagem sobre o HSL é que a luz é confiável: tons com o mesmo L parecem igualmente claros, o que facilita criar paletas, estados de hover e temas escuros. Todos os navegadores atuais aceitam oklch().

- Endereço oficial: https://pradev.com.br/guias/oklch-no-css-cores-e-paletas
- Tipo: Guia
- Publicado em: 2026-10-01
- Atualizado em: 2026-10-01
- Autor: Leonardo Gaertner (https://pradev.com.br/sobre)
- Ferramentas: [Conversor de Cores HEX RGB HSL](https://pradev.com.br/conversor-de-cores), [Gerador de Paleta a partir de HEX](https://pradev.com.br/gerador-de-paleta-a-partir-de-hex), [Verificador de Contraste](https://pradev.com.br/verificador-de-contraste)

## O problema do HSL

No HSL, a luminosidade é uma conta simples sobre os canais RGB, e não a luz que o olho percebe. Por isso `hsl(60 100% 50%)`, um amarelo, parece muito mais claro que `hsl(240 100% 50%)`, um azul, mesmo com os dois em 50%. Uma paleta feita girando o matiz no HSL sai desigual: algumas cores gritam, outras somem, e o contraste do texto muda de uma para outra.

## O que é o OKLCH

O OKLCH é a forma polar do OKLab, um espaço de cor publicado por Björn Ottosson em 2020 e adotado pelo CSS Color 4. O L vai de 0% (preto) a 100% (branco) e acompanha a percepção. O C é o croma: 0 é cinza, e valores em torno de 0,1 a 0,3 são cores vivas. O H é o matiz em graus: perto de 30 é vermelho, 140 verde e 260 azul.

Para ver qualquer cor em OKLCH, cole o HEX no [conversor de cores](https://pradev.com.br/conversor-de-cores). Em código, a conversão passa pelo RGB linear e por duas multiplicações de matriz:

```javascript
// HEX para OKLCH (Björn Ottosson). Devolve l de 0 a 1, c (croma) e h em graus.
function hexParaOklch(hex) {
  const n = parseInt(hex.replace('#', ''), 16);
  const [r, g, b] = [(n >> 16) & 255, (n >> 8) & 255, n & 255].map((v) => {
    const c = v / 255;
    return c <= 0.04045 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4; // sRGB para luz linear
  });
  const l = Math.cbrt(0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b);
  const m = Math.cbrt(0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b);
  const s = Math.cbrt(0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b);
  const L = 0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s;
  const A = 1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s;
  const B = 0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s;
  const C = Math.hypot(A, B);
  const H = C < 1e-4 ? 0 : ((Math.atan2(B, A) * 180) / Math.PI + 360) % 360;
  return { l: L, c: C, h: H };
}

const { l, c, h } = hexParaOklch('#3b82f6');
console.log(`oklch(${(l * 100).toFixed(1)}% ${c.toFixed(3)} ${h.toFixed(1)})`); // oklch(62.3% 0.188 259.8)
```

_JavaScript. HEX para OKLCH, com as matrizes publicadas por Ottosson._

```python
import math


def hex_para_oklch(cor: str) -> tuple[float, float, float]:
    """HEX para OKLCH (Björn Ottosson): l de 0 a 1, croma e matiz em graus."""
    h = cor.lstrip("#")

    def linear(v: int) -> float:
        c = v / 255
        return c / 12.92 if c <= 0.04045 else ((c + 0.055) / 1.055) ** 2.4

    r, g, b = (linear(int(h[i : i + 2], 16)) for i in (0, 2, 4))
    l = (0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b) ** (1 / 3)
    m = (0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b) ** (1 / 3)
    s = (0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b) ** (1 / 3)
    L = 0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s
    A = 1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s
    B = 0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s
    C = math.hypot(A, B)
    H = 0.0 if C < 1e-4 else math.degrees(math.atan2(B, A)) % 360
    return L, C, H


L, C, H = hex_para_oklch("#3b82f6")
print(f"oklch({L * 100:.1f}% {C:.3f} {H:.1f})")  # oklch(62.3% 0.188 259.8)
```

_Python_

## Paletas e variações com OKLCH

Mantendo o C e o H e mudando só o L, você tem tons da mesma família, do quase branco ao quase preto. É assim que o [gerador de paleta](https://pradev.com.br/gerador-de-paleta-a-partir-de-hex) monta a escala de 50 a 950. Para um hover, baixe a luz alguns pontos: `oklch(from var(--marca) calc(l - 0.08) c h)`, com a sintaxe de cor relativa do CSS.

- Cores de estado (sucesso, alerta, erro) com o mesmo L ficam com peso visual parecido.
- No tema escuro, inverter a escala de luz mantém a hierarquia da interface.
- Como o L é confiável, fica mais fácil prever o contraste: o cinza #767676, o mais claro que passa no AA sobre branco, tem L de 56,6%, e o #595959, que passa no AAA, tem 46,4%. Em cores com croma, os valores mudam um pouco, então confira no [verificador de contraste](https://pradev.com.br/verificador-de-contraste).

## Cuidados

Nem toda combinação de L, C e H cabe no sRGB, o espaço das telas comuns. Uma cor com croma alto e luz extrema pode não existir nele, e o navegador a aproxima. Telas de gama ampla (P3) mostram mais cores. Ao gerar paletas em código, reduza o croma até a cor caber, mantendo luz e matiz, como faz o gerador do PraDev.

Para navegadores muito antigos, mantenha um valor em HEX antes: `color: #3b82f6; color: oklch(62.3% 0.188 259.8);`. O navegador que não entende a segunda linha fica com a primeira.

## Perguntas frequentes

### Os navegadores aceitam oklch()?

Sim. Chrome, Edge, Firefox e Safari aceitam oklch() desde 2023. Para navegadores mais antigos, declare antes a mesma cor em HEX.

### Qual a diferença entre OKLCH e LCH?

O LCH vem do CIELAB, de 1976, que distorce os tons azuis ao mudar a luz. O OKLCH corrige isso e é mais previsível para gerar paletas. O CSS aceita os dois.

### Devo trocar todas as cores do projeto para OKLCH?

Não precisa. HEX continua ótimo para guardar cores. O OKLCH ajuda na hora de criar variações e paletas, e você pode converter de um para o outro quando quiser.

## Fontes

- [Björn Ottosson: A perceptual color space for image processing (OKLab)](https://bottosson.github.io/posts/oklab/)
- [W3C: CSS Color Module Level 4, funções oklab() e oklch()](https://www.w3.org/TR/css-color-4/#ok-lab)

## Guias relacionados

- [Contraste de cores e acessibilidade: o que a WCAG exige](https://pradev.com.br/guias/contraste-de-cores-wcag-acessibilidade): O que a WCAG exige de contraste entre texto e fundo (4,5:1 no AA), como a razão é calculada e como corrigir cores que não passam, com código.
