OKLCH e cores CSS Modernas — Por que sua paleta parece errada em alguns navegadores
RGB e HSL foram desenvolvidos para monitores CRT. Aqui está por que OKLCH corrige a uniformidade perceptual, como a função color-mix() altera a mistura de gradientes e o que a sintaxe de cores relativas desbloqueia sem um pré-processador.
Você escolhe um azul para seu botão primário. Ele parece certo no seu navegador. Você abre a versão de staging em um novo MacBook Pro e ele parece… bom — apenas um pouco plano. Seu designer envia uma captura de tela feita em seu iPhone e o mesmo botão parece muito mais vivo. O mesmo código hexadecimal. Exibição diferente.
É a diferença do P3. E na verdade é a parte menos interessante do motivo pelo qual o modelo de cores do CSS que você tem usado está falhando. O problema maior está na matemática por trás do HSL.
O teto do sRGB
Cada cor hexadecimal e rgb() valor que você já escreveu vive no espaço de cores sRGB — um padrão introduzido em 1996 para monitores de CRT. O espaço de cores sRGB cobre aproximadamente 35% das cores visíveis ao olho humano. O espaço de cores P3, usado por todos os iPhones desde 2017 e pela maioria dos MacBooks desde 2016, cobre cerca de 45%.
Quando você escreve #3b82f6, essa cor é limitada ao sRGB. Em um display P3, o navegador poderia teoricamente renderizar um azul mais saturado — mas seu CSS não está pedindo isso. Você está deixando o potencial do display inutilizado por padrão.
Para acessar cores P3 diretamente, você usaria color(display-p3 0.2 0.4 0.9). Isso funciona. Mas não é o motivo pelo qual o OKLCH importa. O maior problema está na suposição central do HSL.
A luz do HSL é uma mentira
O HSL foi uma melhoria genuína em relação ao hexadecimal. Hue, Saturação, Lightness — conceitualmente sensível, editável por humanos. O problema: a "L" não significa o que você pensa que significa.
Coloque amarelo em hsl(60, 100%, 50%) e azul em hsl(240, 100%, 50%) lado a lado. Ambos estão exatamente na luz 50%.
.yellow { background: hsl(60, 100%, 50%); }
.blue { background: hsl(240, 100%, 50%); }
O amarelo parece quase branco. O azul parece meio escuro. Eles não estão nem perto da mesma percepção de brilho. Isso é a não uniformidade perceptual do HSL — o eixo L não mapeia como a visão humana processa a brilhância.
Isso cria um problema real de manutenção ao construir escalas de cores. Se você gerar uma escala de 9 etapas aumentando os valores de L no HSL, seus amarelos e cianos ficarão muito claros enquanto seus azuis e roxos ficarão opacos. Você acaba ajustando valores manualmente, o que anula completamente o propósito de ter um método sistemático.
OKLCH: construído para a percepção
O OKLCH foi desenvolvido por Björn Ottosson em 2020. Ele se baseia no CIELAB (um espaço de cores perceptível dos anos 1970) mas corrige os deslocamentos conhecidos de cor — especialmente o problema do roxo/azul, onde ajustar a saturação causaria um deslocamento visível na percepção da cor.
Os três canais:
- L (Luminosidade) — de 0 a 1, uniforme perceptivamente. L 0.5 em amarelo parece a mesma luminosidade que L 0.5 em azul. Na verdade.
- C (Saturação) — começa em 0 (cinza), aumenta até cerca de 0.3–0.4 para cores altamente saturadas. Sem limite fixo — o limite superior varia com a cor e o gamut alvo.
- H (Matiz) — de 0 a 360 graus, aproximadamente comparável ao eixo de cor do HSL.
Aqui está o azul Tailwind blue-500 em ambos os sistemas:
/* sRGB hex */
background: #3b82f6;
/* OKLCH equivalent — same color, different notation */
background: oklch(0.623 0.214 259.1);
/* Push chroma past sRGB — more vivid blue on P3 displays, clips gracefully on sRGB */
background: oklch(0.623 0.27 259.1);
Esse último valor está fora do gamut do sRGB. Navegadores em displays com suporte ao P3 renderizam a versão mais viva; navegadores mais antigos clipeiam para a versão mais próxima do sRGB. Progressão com zero esforço.
color-mix() e por que o espaço de cores muda a mistura
color-mix() lançada em Chrome 111, Firefox 113 e Safari 16.2. Ela mistura duas cores em uma proporção — simples o suficiente. Mas o espaço de cores que você especifica muda significativamente o resultado.
/* Mixes through sRGB — midpoint is a washed-out brown-grey */
background: color-mix(in srgb, oklch(0.7 0.2 30), oklch(0.7 0.2 270));
/* Mixes through the OKLCH color wheel — midpoint is a vivid purple */
background: color-mix(in oklch, oklch(0.7 0.2 30), oklch(0.7 0.2 270));
Quando você mistura laranja e azul no sRGB, você está média os valores brutos dos canais. O ponto médio passa por um tom desaturado de marrom-escuro. No OKLCH, você está interpolando ao longo da roda de cores — você cai em um roxo vibrante. O que é correto depende da intenção, mas para transições de interface, gradientes e estados de hover, a interpolação do OKLCH é quase sempre o que você deseja.
Uma aplicação prática: gerar um estado desativado sem codificar um segundo valor hexadecimal.
.button--disabled {
background: color-mix(in oklch, var(--color-primary) 40%, white);
cursor: not-allowed;
}
Sintaxe de cor relativa
A sintaxe de cor relativa (Chrome 119+, Firefox 128+, Safari 16.4+) permite derivar uma nova cor modificando canais individuais de uma cor existente:
:root {
--brand: oklch(0.623 0.214 259.1);
}
.button:hover {
/* Lighten by 8% lightness units */
background: oklch(from var(--brand) calc(l + 0.08) c h);
}
.button:active {
/* Darken and reduce chroma slightly */
background: oklch(from var(--brand) calc(l - 0.08) calc(c - 0.02) h);
}
.button--muted {
/* Drop chroma to near-zero: perceptual grey at the same lightness */
background: oklch(from var(--brand) l 0.03 h);
}
Isso substitui a sintaxe do Sass lighten(), darken()e, e desaturate() por CSS nativo — sem pré-processador, sem etapa de build, sem valores hexadecimais paralelos para manter sincronizados. E porque você está no OKLCH, "esclarecer" realmente parece mais claro em todos os tons da sua paleta, e não apenas em alguns deles.
Uma limitação real: restrições complexas de canal (como clarear a saturação para permanecer dentro do gamut) exigem cadeias longas de calc() que se tornam confusas rapidamente. Para mudanças simples de luminosidade e saturação, a sintaxe é limpa. Para qualquer coisa mais sofisticada, calcular valores no momento da compilação e gerar propriedades personalizadas é mais manutenível.
Suporte nos navegadores em 2026
| Recurso | Cromo | Raposa de fogo | Safári |
|---|---|---|---|
oklch() | 111+ | 113+ | 15.4+ |
color-mix() | 111+ | 113+ | 16.2+ |
| Sintaxe de cor relativa | 119+ | 128+ | 16.4+ |
color(display-p3) | 111+ | 113+ | 10+ |
O suporte global para oklch() está acima de 90% até meados de 2026. Os atrasados são navegadores empresariais baseados em Chromium e qualquer coisa ainda rodando com Firefox abaixo de 113. Se esses navegadores estiverem em seu grupo de usuários, uma falha de duas linhas é tudo o que você precisa:
.button {
background: #3b82f6; /* sRGB fallback */
}
@supports (background: oklch(0 0 0)) {
.button {
background: oklch(0.623 0.214 259.1);
}
}
Na prática: se seus dados de análise confirmarem Chrome 111+, Firefox 113+ e Safari 15.4+, você pode ignorar completamente a falha. O @supports wrapper é para tranquilidade em ferramentas internas onde você não controla as versões dos navegadores.
Conversão da sua paleta existente
O ponto de fricção com a adoção do OKLCH é passar de seus valores atuais em hex para coordenadas OKLCH e entender o que os canais significam para cada cor. O Conversor de Espaço de Cor Unificado gera a conversão em ambas as direções — cole um valor hexadecimal ou HSL, obtenha OKLCH, e então comece a ajustar L e C a partir de um ponto de referência real. Ele suporta HSL, RGB, Lab, LCH, HSV e OKLCH em um único lugar, o que é útil quando você está trabalhando com um arquivo do Figma que fornece valores em hex e precisa chegar a valores OKLCH que você pode raciocinar.
Como realmente migrar
Você não precisa reescrever tudo de uma vez. Uma sequência prática:
- Comece com cores interativas — seus tokens primários, secundários e destrutivos. Essas são as que você já está gerando variações de hover, ativo e desativado. O OKLCH + sintaxe de cor relativa substitui essa lógica com CSS nativo imediatamente.
- Deixe as cores estáticas em hex por enquanto — texto, fundos, bordas. Elas não estão sendo manipuladas programaticamente, então não há retorno para converter-as ainda.
- Construa o próximo sistema novo do zero em OKLCH — é aqui que as vantagens de uniformidade perceptiva se tornam estruturais. O seu escalão neutro no passo 500 realmente ficará no ponto visual médio, e suas cores saturadas serão consistentes em todos os tons sem ajustes manuais.
O objetivo não é o OKLCH por si só. É ter um sistema de cores onde a matemática corresponde ao que os olhos veem — para que você pare de compensar manualmente sempre que precisar de um azul ligeiramente mais claro.
Você também pode gostar
Instale nossas extensões
Adicione ferramentas de IO ao seu navegador favorito para acesso instantâneo e pesquisa mais rápida
恵 O placar chegou!
Placar é uma forma divertida de acompanhar seus jogos, todos os dados são armazenados em seu navegador. Mais recursos serão lançados em breve!
Ferramentas essenciais
Ver tudo Novas chegadas
Ver tudoAtualizar: Nosso ferramenta mais recente Foi adicionado em 15 de junho de 2026
