color theoryMay 3, 202612 min read

Cor OKLCH no CSS moderno: por que ela vence e como colocar em produção

Um guia prático de cor OKLCH em CSS. Por que o hex quebrou em escala, como o OKLCH corrige a deriva de luminosidade, o caminho de migração em quatro passos e a rampa de paleta perceptualmente uniforme que todo design system deveria entregar em 2026.

By Boone
XLinkedIn
oklch color modern css

Cor OKLCH no CSS moderno: por que ela vence e como colocar em produção

OKLCH é o primeiro espaço de cor que o CSS entregou e sobre o qual designers conseguem de fato raciocinar. Os times que ainda montam paletas em hex estão perdendo em silêncio toda discussão de contraste e dark mode que nem sabiam que estavam tendo.

Hex nunca foi um espaço de cor, era uma serialização

Hex é um atalho para sRGB. #4A90E2 não é uma especificação de cor, é uma trinca de valores de canal vermelho, verde e azul comprimida em seis caracteres. O sRGB foi projetado para monitores CRT no começo dos anos 1990, não para a percepção visual humana.

A consequência é que dois valores hex podem ocupar a mesma posição numérica de "brilho" na sua paleta e parecer completamente diferentes aos seus olhos. O blue-500 da maioria dos design systems parece mais escuro que o yellow-500, mesmo quando os dois ocupam a mesma posição relativa na rampa. Isso não é problema de gosto. É um problema de matemática embutido no sistema de coordenadas.

"Hex nunca foi um espaço de cor, era uma serialização, e desde então a gente discute luminosidade."

O HSL fingiu consertar e não consertou

O HSL chegou e deu linguagem aos designers: matiz, saturação, luminosidade. Parecia um sistema. Não era. O canal de luminosidade do HSL ainda mapeia para valores sRGB por baixo dos panos, o que significa que o HSL herda os mesmos problemas perceptuais do hex.

hsl(220, 70%, 50%) e hsl(45, 70%, 50%) têm, nominalmente, a mesma luminosidade. Abra os dois lado a lado. O amarelo parece bem mais claro. O HSL te deu palavras melhores para a mesma matemática quebrada.

O OKLCH é perceptualmente uniforme

O OKLCH é construído sobre o espaço de cor OKLab, desenvolvido por Björn Ottosson em 2020 justamente para resolver a não uniformidade perceptual dos espaços anteriores. O L em OKLCH significa luminosidade percebida, calibrada para a forma como o sistema visual humano realmente responde à luz.

Valores de L iguais em OKLCH significam brilho percebido igual. Não aproximadamente igual. Não "geralmente igual se o chroma for parecido". Igual. Essa é a propriedade que nenhum espaço de cor anterior do CSS conseguiu entregar, e ela muda tudo na forma como você raciocina sobre geração de paletas.

As três razões pelas quais o OKLCH vence

Luminosidade perceptualmente uniforme, interpolação de matiz previsível e suporte a gamut amplo. Cada uma corrige um bug específico da sua paleta atual, e juntas compõem um fluxo de cor que escala entre temas, componentes e tipos de tela.

Conceito em voxel mostrando três blocos empilhados que representam as três vitórias estruturais do OKLCH sobre hex e HSL: luminosidade perceptual, interpolação de matiz sensata e alcance de gamut amplo
Conceito em voxel mostrando três blocos empilhados que representam as três vitórias estruturais do OKLCH sobre hex e HSL: luminosidade perceptual, interpolação de matiz sensata e alcance de gamut amplo

Razão um: a deriva de luminosidade morreu

Em sistemas hex e HSL, a deriva de luminosidade é o imposto invisível que você paga em toda paleta. Você define blue-50 e amber-50 no que parece certo a olho, eles divergem em telas diferentes, brigam no dark mode, e a conta de contraste nunca fecha direito.

Em OKLCH, blue-50 e amber-50 têm o mesmo número de luminosidade, e esse número representa o mesmo brilho percebido. O Tailwind v4 migrou toda a sua paleta para OKLCH exatamente por isso. Se você usa as escalas de cor do Radix UI, já se beneficia da uniformidade perceptual mesmo sem nunca ter visto a palavra OKLCH na documentação.

Razão dois: a interpolação de matiz é sensata

Gradientes em CSS com interpolação sRGB viajam pelo cubo de cor RGB, não pelo espaço perceptual. Um gradiente de azul para amarelo em sRGB passa por um meio cinza lamacento porque a diagonal do RGB cruza perto do eixo acromático. Não é artístico. É um acidente de geometria.

A interpolação de gradiente em OKLCH percorre o ângulo de matiz ao longo do anel perceptual. Do azul ao amarelo em OKLCH passa por ciano e verde, que é o que o seu olho espera. A lama cinza sumiu. Isso importa para gradientes de UI, transições de cor animadas e qualquer ferramenta de geração de paleta que produza passos intermediários.

Razão três: P3 e Rec2020 ficam ao alcance

O hex não consegue descrever cores fora do sRGB. Todo iPhone desde 2016, todo notebook moderno com painel de gamut amplo e a maioria dos monitores de consumo novos exibem cores que existem no gamut P3 mas não têm endereço em hex. Você vem deixando cor saturada e vívida na mesa porque seu sistema de coordenadas não sabia nomeá-la.

O OKLCH descreve cores P3 e Rec2020 nativamente. oklch(0.60 0.28 260) é um azul vívido que existe no P3 mas está fora do gamut sRGB. Os navegadores modernos sabem lidar com isso, e a orientação de cor Display P3 da Apple aponta nessa direção há anos. O design system que migra para OKLCH agora também é o design system pronto quando o P3 virar a expectativa padrão.

A migração em quatro passos do hex para o OKLCH

Auditar, converter, regenerar, reauditar. A migração é mecânica para tokens primitivos e exige julgamento para tokens semânticos. Uma migração completa de um design system de porte médio leva dias, não semanas. Ancorar os novos tokens em uma arquitetura limpa de variáveis do Figma antes de começar é o que mais economiza tempo.

Passo um: audite a paleta existente

Exporte todos os tokens de cor do seu sistema. Converta cada valor hex para OKLCH com uma ferramenta como oklch.com ou o plugin PostCSS OKLCH. Ordene pelo valor de L e olhe a coluna de luminosidade ao longo dos matizes.

Os bugs se anunciam na hora. O blue-300 vai estar em L=0.72 enquanto o yellow-300 está em L=0.87. Tokens que deveriam ter o mesmo peso visual estão longe disso. Essa auditoria é a evidência que torna a decisão de migrar fácil de justificar para qualquer um que resista.

Passo dois: converta os primitivos para OKLCH

Pegue a escala primitiva, a rampa numerada bruta em vez dos tokens semânticos, e converta para OKLCH. Arredonde os valores de luminosidade para passos consistentes nos onze estágios: 0.97, 0.93, 0.86, 0.75, 0.65, 0.54, 0.45, 0.37, 0.27, 0.19, 0.13.

Não tente preservar os valores hex originais exatamente. O objetivo é corrigir a inconsistência. Um blue-500 convertido e um red-500 convertido não serão idênticos pixel a pixel aos valores antigos, e esse é o objetivo inteiro. O sistema está ficando melhor, não só diferente.

Passo três: regenere as rampas

Com passos de luminosidade limpos e consistentes, regenerar rampas entre matizes vira uma operação de tabela. Defina a coluna L, escolha o chroma de cada matiz (azuis normalmente suportam mais chroma que marrons e amarelos antes de estourar), ajuste a coluna H e gere.

O resultado é que blue-500 e red-500 passam a ter o mesmo peso visual pela primeira vez no seu sistema. As decisões de paleta de cores da marca que antes eram palpites arbitrários viram escolhas fundamentadas, com uma coordenada para apontar.

Passo quatro: reaudite a acessibilidade

Paleta nova, nova passada de contraste. O OKLCH facilita a previsão de contraste porque a luminosidade agora significa o que diz. Combinar dois tokens com valores de L conhecidos já dá uma boa estimativa da taxa de contraste antes mesmo de abrir o verificador.

Rode verificações de contraste WCAG e APCA em todos os pares de tokens semânticos. Sinalize os pares que não cumprem mais os requisitos e ajuste chroma ou luminosidade do token que falhou. Uma boa passada de contraste de cor acessível em uma paleta OKLCH costuma trazer menos surpresas que a equivalente em uma paleta hex, porque os passos de luminosidade já estavam errados antes e agora não estão.


Quer um sistema de cor que se sustente entre modos, matizes e telas modernas sem deriva de luminosidade? A Brainy desenha sistemas de paleta nativos em OKLCH que saem como variáveis do Figma, propriedades customizadas de CSS e tokens do Tailwind, já com a passada de contraste feita.


As quatro armadilhas do OKLCH

Clamping de gamut fora da faixa, corte de chroma, tratamento de alpha e lacunas de ferramentas. Cada uma pega times novos em OKLCH, e cada uma tem uma correção específica que leva minutos para aplicar quando você sabe o que procurar.

ArmadilhaO que aconteceCorreção
Clamping fora do gamutValores de chroma alto caem fora do sRGB e são cortados pelo navegador, às vezes deslocando o matizIsole cores só P3 com @media (color-gamut: p3)
Corte de chromaO clamping muda um pouco o matiz, não só a saturaçãoMantenha o chroma seguro para sRGB abaixo de ~0.20 para ampla compatibilidade
Tratamento de alphaoklch(0.55 0.20 260 / 0.5) funciona em preenchimentos estáticos; alguns caminhos de interpolação em navegadores antigos quebramTeste alpha em gradientes e transições, não só em cores estáticas
Lacunas de ferramentasO seletor de cor nativo do Figma não expõe OKLCH diretamenteUse o Tokens Studio ou defina tokens em CSS e referencie pelo painel de código do Figma

O problema de gamut é o que mais machuca. Quando você escreve oklch(0.60 0.32 260), esse valor de chroma está fora do sRGB. Navegadores desktop lidam com isso cortando para a cor sRGB mais próxima, o que pode deslocar o matiz aparente. A correção é manter chroma seguro para sRGB nos tokens base ou isolar os valores de gamut amplo atrás de uma media query e manter uma declaração de fallback acima.

A rampa de paleta OKLCH que funciona

Uma rampa prática de 11 passos com degraus de luminosidade consistentes, usando azul no matiz 260 como referência. Os passos de luminosidade são idênticos em todos os matizes do seu sistema. Só chroma e matiz mudam por família de cor.

css
:root { --blue-50: oklch(0.97 0.02 260); --blue-100: oklch(0.93 0.05 260); --blue-200: oklch(0.86 0.09 260); --blue-300: oklch(0.75 0.14 260); --blue-400: oklch(0.65 0.18 260); --blue-500: oklch(0.54 0.22 260); --blue-600: oklch(0.45 0.20 260); --blue-700: oklch(0.37 0.17 260); --blue-800: oklch(0.27 0.13 260); --blue-900: oklch(0.19 0.09 260); --blue-950: oklch(0.13 0.06 260); }

Para gerar vermelho (matiz 25), âmbar (matiz 75) ou verde (matiz 145), mantenha a coluna L idêntica nos onze estágios. Ajuste o C conforme a capacidade natural de chroma do matiz: amarelos e verdes suportam menos chroma que azuis antes de estourar o sRGB. Ajuste o H para o matiz desejado. Esse é o sistema de paleta inteiro.

O sistema de cores para dark mode construído sobre essa rampa usa tokens semânticos que alternam entre primitivos por passo de L e matiz, não sobrescrevendo valores hex manualmente um a um.

Conceito em voxel de uma rampa de cor de 11 passos com luminosidade percebida uniforme entre os estágios, ilustrando como o OKLCH mantém o peso visual consistente de 50 a 950
Conceito em voxel de uma rampa de cor de 11 passos com luminosidade percebida uniforme entre os estágios, ilustrando como o OKLCH mantém o peso visual consistente de 50 a 950

Suporte dos navegadores e a janela segura de migração

O OKLCH é suportado em todo grande navegador lançado desde 2023. Chrome 111, Safari 15.4, Firefox 113 e Edge 111 entregam suporte completo a OKLCH. A cobertura global fica acima de 93% em meados de 2025. A janela de migração está aberta.

NavegadorSuporte a OKLCHDesde
ChromeCompleto111 (mar 2023)
SafariCompleto15.4 (mar 2022)
FirefoxCompleto113 (mai 2023)
EdgeCompleto111 (mar 2023)
Samsung InternetCompleto21 (2023)

O fallback para qualquer navegador sem suporte a OKLCH é uma linha. Declare primeiro o fallback em hex, depois o valor OKLCH. Navegadores que não entendem OKLCH o ignoram e usam o hex. Os que entendem usam o valor melhor.

css
color: #4a7de8; /* sRGB fallback */ color: oklch(0.54 0.22 260); /* OKLCH for modern browsers */

O Tailwind v4 gera sua paleta nativamente em OKLCH. Linear, os design tokens Sail da Stripe e a orientação de cor para desenvolvedores da Apple caminharam todos para sistemas perceptualmente uniformes. A indústria já chegou lá. A questão é quando o seu time entra.

FAQ

O OKLCH é difícil de aprender?

O sistema de coordenadas é diferente do hex ou do HSL, mas não é complexo. L é a luminosidade de 0 a 1. C é o chroma, grosso modo o quão saturada é a cor. H é o matiz em graus. Quando você internaliza que L significa brilho percebido e C significa colorido, o sistema fica intuitivo mais rápido do que o HSL ficou.

Posso usar OKLCH no Figma hoje?

O Figma não expõe OKLCH nativamente no seletor de cor em 2025. O fluxo prático é definir tokens em OKLCH em um arquivo de tokens via Tokens Studio ou em um arquivo de variáveis CSS sincronizado com as variáveis do Figma, e depois usar a exportação de código do Figma para verificar os valores. O motor de renderização do Figma cuida da conversão internamente.

O OKLCH quebra meus valores hex existentes?

Não. Você pode introduzir OKLCH de forma incremental, token por token. Seus valores hex existentes continuam funcionando exatamente como antes. A migração é aditiva, não uma troca.

Qual é a diferença entre LCH e OKLCH?

O LCH é baseado no espaço de cor CIELAB, que é perceptualmente uniforme mas tem problemas de linearidade de matiz, particularmente na faixa azul-violeta. O OKLCH é baseado no OKLab, que corrige esses desvios de matiz. Para trabalho prático de design, o OKLCH é a melhor escolha porque sua interpolação de matiz produz menos surpresas.

Como converto hex para OKLCH?

Use oklch.com, o plugin PostCSS oklch ou o playground da especificação CSS Color 4. Cole seu valor hex, leia as coordenadas OKLCH, arredonde L e C para duas casas decimais e H para o grau inteiro mais próximo. Esse é o valor do seu token.

O OKLCH afeta os requisitos de acessibilidade?

Os requisitos de contraste da WCAG são definidos sobre a luminância relativa do sRGB, não sobre a luminosidade do OKLCH. O APCA é mais alinhado a modelos perceptuais e mapeia de forma mais natural para os valores de L do OKLCH. Na prática, o OKLCH torna a previsão de contraste mais intuitiva porque o L acompanha o brilho percebido, mas você ainda precisa passar os pares de tokens semânticos por um verificador de contraste. O processo é o mesmo, só que mais fácil de antecipar.

A mudança que o OKLCH realmente destrava

O OKLCH não é moda. É a primeira vez que o CSS entrega um espaço de cor projetado em torno de como os olhos humanos percebem cor, e as ferramentas já amadureceram o bastante para que a migração seja prática hoje para qualquer time disposto a dedicar alguns dias focados.

Os times que migram agora ganham três coisas de uma vez: uma paleta que se sustenta no dark mode sem sobrescritas manuais, um comportamento de contraste que combina com o sistema de coordenadas e uma base que se estende ao P3 sem reescrita futura. Os times que esperam vão continuar tendo a mesma discussão sobre por que o blue-300 parece mais pesado que o orange-300, e a resposta continuará a mesma. O sistema de coordenadas nunca foi projetado para essa função.

Se você quer construir a arquitetura completa de tokens sobre essa paleta, o paper de arquitetura de variáveis do Figma cobre a camada semântica. Para a aplicação disso em dark mode, sistemas de cor para dark mode continua de onde este termina.

Quer isso feito por nós? Contrate a Brainy.

Want a color system that holds up across modes, hues, and modern displays without lightness drift? Brainy designs OKLCH-native palette systems that ship as Figma variables, CSS custom properties, and Tailwind tokens with the contrast pass already done.

Get Started

More from Brainy Papers

Keep reading