Tutoriais

Interpolação de Cores em CSS: Por Que o OKLCH Vence

9 min de leitura

Toda vez que o CSS mescla duas cores — em um gradiente, em color-mix() ou em uma transição — ele realiza interpolação de cores: calculando valores intermediários entre uma cor de início e uma cor de fim. Durante a maior parte da história da web, esse cálculo acontecia no espaço de cores sRGB, e os resultados frequentemente eram opacos, dessaturados ou perceptualmente desiguais. Com o CSS moderno, agora você pode escolher o espaço de cores para interpolação. A escolha importa enormemente, e o OKLCH consistentemente produz os melhores resultados.

Este tutorial explica por que a interpolação RGB falha, onde o HSL fica aquém e por que o OKLCH é o padrão correto para gradientes e mistura de cores em 2024 e além.

O Problema da Interpolação RGB: Pontos Intermediários Opacos

Quando você escreve um gradiente CSS sem especificar um espaço de cores, o navegador interpola em sRGB — ele calcula cores intermediárias misturando linearmente os valores dos canais R, G e B de forma independente.

Isso parece razoável, mas falha gravemente quando os dois extremos passam pelo meio do cubo sRGB. Considere um gradiente do vermelho ao verde:

/* Padrão: interpola em sRGB */
background: linear-gradient(to right, #FF0000, #00FF00);

O ponto intermediário deste gradiente em sRGB é #808000 — um azeitona opaco. Matematicamente, RGB 128, 128, 0 está exatamente no meio entre vermelho e verde em valores de canal. Mas perceptualmente, parece nada com um ponto intermediário vibrante entre dois primários vívidos. O gradiente mergulha em um vale escuro e opaco antes de clarear do outro lado.

O problema fundamental é que sRGB não é perceptualmente uniforme. Passos numéricos iguais em R, G e B não correspondem a passos iguais em cor percebida ou brilho. O cubo sRGB foi projetado para hardware de exibição, não para a visão humana.

/* Você pode forçar sRGB explicitamente */
background: linear-gradient(in srgb, red, blue);

/* Ou use a sintaxe legada (mesmo resultado) */
background: linear-gradient(red, blue);

Ambos produzem os mesmos pontos intermediários dessaturados. O problema é o próprio espaço de cores, não a sintaxe.

O Problema do Gamma

Há outra sutileza: os valores sRGB são codificados em gamma. Valores sRGB brutos de 0,5 não correspondem a 50% da luz física emitida por um display. O ponto intermediário perceptual real de um gradiente precisa ser calculado na luz linear, não no sRGB codificado em gamma. O CSS nível 4 introduziu in srgb-linear para resolver isso:

background: linear-gradient(in srgb-linear, red, blue);

O sRGB linear é melhor do que o sRGB com gamma para transições de luminância, mas ainda não resolve os problemas de mudança de matiz e queda de saturação porque ainda é um espaço RGB retangular.

Mudanças de Matiz no HSL

O HSL foi introduzido como uma alternativa mais legível por humanos ao RGB. Sua representação cilíndrica — Matiz em um ângulo de 0–360, Saturação e Luminosidade como porcentagens — facilita o raciocínio sobre relações de cores. Mas a interpolação HSL tem seu próprio modo de falha característico: mudanças de matiz.

Quando você interpola entre duas cores HSL, o navegador percorre o arco mais curto do círculo de matiz. Se você for de um vermelho quente (hsl(10, 100%, 50%)) para um azul frio (hsl(220, 100%, 50%)), o caminho mais curto passa pelo roxo e violeta — o que pode ou não ser o que você quer.

Mas o problema mais profundo é que a Luminosidade do HSL não é perceptualmente uniforme. Um amarelo em hsl(60, 100%, 50%) parece dramaticamente mais brilhante do que um azul em hsl(240, 100%, 50%), mesmo que compartilhem o mesmo valor L. Quando você interpola do amarelo para o azul em HSL, o brilho percebido oscila e cai de maneiras que parecem incoerentes.

/* Gradiente HSL — o brilho perceptual é desigual entre as matizes */
background: linear-gradient(in hsl, hsl(60 100% 50%), hsl(240 100% 50%));

O ponto intermediário deste gradiente em hsl(150, 100%, 50%) é um verde vívido que parece perceptualmente mais brilhante do que qualquer um dos extremos. O gradiente atinge seu pico no meio em vez de fazer a transição suavemente.

A interpolação HSL também tem um problema de arco longo: o ângulo de matiz envolve em 360°, e se você interpolar de hsl(350, ...) (próximo ao vermelho) para hsl(20, ...) (laranja), o HSL pode percorrer o longo caminho ao redor do círculo de matiz por azul, verde e amarelo em vez do caminho curto pelo vermelho.

OKLCH: Consistência e Uniformidade Perceptual

O OKLCH é uma forma cilíndrica do espaço de cores Oklab, projetado por Björn Ottosson em 2020 especificamente para resolver as deficiências de uniformidade perceptual dos espaços de cores anteriores. Seus três canais — L (luminosidade), C (croma) e H (ângulo de matiz) — são calibrados para que mudanças numéricas iguais em L produzam mudanças iguais no brilho percebido, independentemente da matiz.

Quando você interpola entre duas cores OKLCH, obtém:

  1. Brilho percebido consistente ao longo da transição — sem mergulhar em pontos intermediários escuros ou picos de brilho súbitos.
  2. Croma preservado — os pontos intermediários permanecem vívidos porque o croma é interpolado independentemente da matiz.
  3. Caminhos de matiz mais curtos e intuitivos — os ângulos de matiz do OKLCH são distribuídos em ordem perceptual, então a interpolação percorre as matizes intermediárias esperadas.
/* Gradiente OKLCH — vívido, perceptualmente uniforme */
background: linear-gradient(in oklch, red, blue);

Um gradiente do vermelho ao azul em OKLCH percorre magenta e roxo vívidos — os pontos intermediários perceptualmente intuitivos. Permanece saturado e uniformemente brilhante ao longo de todo o percurso.

Comparação Lado a Lado

Gradiente Cor do Ponto Intermediário Qualidade Percebida
in srgb do vermelho ao verde #808000 — azeitona opaco Vale escuro e opaco
in hsl do amarelo ao azul Pico de verde vívido Brilho desigual, pico de cor
in oklch do vermelho ao verde Amarelo quente vívido Suave, saturado, uniforme

Para ver a diferença você mesmo, use o Gerador de Gradientes que permite visualizar gradientes em diferentes espaços de cores.

Como Converter Suas Cores para OKLCH

Você não precisa reescrever cada valor de cor no seu CSS. O sinalizador in oklch em um gradiente instrui o navegador a converter as cores dos extremos para OKLCH antes de interpolar, depois converter de volta ao espaço de cores de saída. Você pode manter seus valores HEX:

/* Esses extremos HEX são automaticamente convertidos para OKLCH na interpolação */
background: linear-gradient(in oklch, #FF5733, #3498DB);

#FF5733 é aproximadamente oklch(0.63 0.24 27) e #3498DB é aproximadamente oklch(0.63 0.14 232). Use o Conversor de Cores para verificar os valores OKLCH de qualquer código HEX antes de projetar um gradiente, para saber com antecedência o que a interpolação percorrerá.

A Função color-mix()

A função CSS color-mix() é a API declarativa para misturar duas cores, disponível em todos os navegadores modernos desde 2023. Sua sintaxe inclui o espaço de cores de interpolação como primeiro argumento:

color: color-mix(in oklch, #FF5733 50%, #3498DB);

Isso mistura #FF5733 e #3498DB em proporções iguais no espaço OKLCH. O resultado é um intermediário vívido que parece um ponto perceptual real entre as duas cores — não uma média sRGB opaca.

Usos Práticos de color-mix()

Criando variantes transparentes:

:root {
  --brand: #2563EB;
  --brand-10: color-mix(in oklch, var(--brand) 10%, transparent);
  --brand-20: color-mix(in oklch, var(--brand) 20%, transparent);
  --brand-50: color-mix(in oklch, var(--brand) 50%, transparent);
}

Tingindo em direção ao branco ou preto:

:root {
  --brand: #2563EB;
  --brand-light: color-mix(in oklch, var(--brand) 70%, white);
  --brand-dark:  color-mix(in oklch, var(--brand) 70%, black);
}

Essa é a mesma ideia de um gerador de matizes, mas completamente em CSS, sem pré-processamento. O resultado na tingimento OKLCH parece mais natural do que operações equivalentes em HSL porque o croma se desloca apropriadamente ao se aproximar do branco ou do preto.

Derivação de estado hover:

.button {
  background: var(--brand);
}
.button:hover {
  background: color-mix(in oklch, var(--brand) 80%, black);
}

Aviso: color-mix() em sRGB

Se você omitir o argumento in <colorspace>, color-mix() usa interpolação sRGB por padrão:

/* Isso usa sRGB — pode produzir resultados opacos */
color: color-mix(#FF5733, #3498DB);

/* Correto: especifique o espaço */
color: color-mix(in oklch, #FF5733, #3498DB);

Sempre especifique in oklch (ou outro espaço preferido) explicitamente. O padrão sRGB é preservado para compatibilidade retroativa, mas raramente é a melhor escolha.

Espaço de Cores de Interpolação de Gradiente

A sintaxe moderna do CSS permite especificar o espaço de cores de interpolação diretamente em uma declaração de gradiente usando in <colorspace> após a palavra-chave de direção:

/* sRGB (padrão, frequentemente opaco) */
background: linear-gradient(to right, red, blue);

/* sRGB linear (melhor luminância, ainda tem problemas de matiz) */
background: linear-gradient(in srgb-linear to right, red, blue);

/* HSL (mudanças de matiz, brilho desigual) */
background: linear-gradient(in hsl to right, red, blue);

/* OKLCH (recomendado: vívido, perceptualmente uniforme) */
background: linear-gradient(in oklch to right, red, blue);

/* Oklab (também excelente, sintaxe menos intuitiva) */
background: linear-gradient(in oklab to right, red, blue);

Esta sintaxe aplica-se a todos os tipos de gradiente: linear-gradient, radial-gradient e conic-gradient.

Direção de Interpolação de Matiz no OKLCH

Para interpolação de matiz especificamente, você pode controlar se o gradiente toma o arco mais curto ou mais longo ao redor do círculo de matiz:

/* Arco mais curto (padrão) */
background: linear-gradient(in oklch, hsl(30 100% 50%), hsl(270 100% 50%));

/* Arco mais longo — percorre amarelo, verde, ciano, depois roxo */
background: linear-gradient(in oklch longer hue, hsl(30 100% 50%), hsl(270 100% 50%));

/* Arco crescente — sempre vai na direção do ângulo de matiz crescente */
background: linear-gradient(in oklch increasing hue, hsl(30 100% 50%), hsl(270 100% 50%));

A palavra-chave shorter hue (padrão) fornece o resultado mais natural na maioria dos casos. A variante longer hue é útil para efeitos arco-íris ou quando você especificamente quer que o gradiente percorra uma ampla parte do espectro de matiz.

Gradientes com Múltiplas Paradas

A interpolação OKLCH se torna ainda mais valiosa para gradientes com múltiplas paradas, porque cada segmento interpola por pontos intermediários perceptualmente vívidos:

/* Um gradiente arco-íris que permanece vívido ao longo de todo o percurso */
background: linear-gradient(
  in oklch to right,
  oklch(0.70 0.20 30),   /* laranja-vermelho */
  oklch(0.80 0.20 90),   /* amarelo */
  oklch(0.75 0.20 150),  /* verde */
  oklch(0.65 0.20 240),  /* azul */
  oklch(0.60 0.20 300)   /* roxo */
);

Como os valores de L e C são perceptualmente calibrados, definir valores similares em todas as paradas resulta em um arco-íris que parece naturalmente brilhante e saturado, sem as quedas de luminância comuns em arco-íris sRGB.

Suporte de Navegadores

A sintaxe in <colorspace> de gradiente é suportada em todos os principais navegadores:

  • Chrome/Edge: Suporte completo desde a versão 111 (março de 2023)
  • Firefox: Suporte completo desde a versão 113 (maio de 2023)
  • Safari: Suporte completo desde a versão 16.2 (dezembro de 2022)

Para navegadores mais antigos, use graciosamente a sintaxe legada primeiro:

/* Fallback: gradiente sRGB */
background: linear-gradient(to right, #FF5733, #3498DB);

/* Moderno: interpolação OKLCH */
@supports (background: linear-gradient(in oklch, red, blue)) {
  background: linear-gradient(in oklch to right, #FF5733, #3498DB);
}

Principais Conclusões

  • A interpolação sRGB (o padrão CSS) produz pontos intermediários opacos e dessaturados quando gradientes passam perto do centro do cubo sRGB — particularmente visível em gradientes vermelho-verde e de cores complementares.
  • A interpolação HSL evita alguns problemas do RGB, mas introduz brilho percebido inconsistente — seu canal de Luminosidade não é perceptualmente uniforme — e pode produzir caminhos de matiz inesperados.
  • A interpolação OKLCH produz pontos intermediários vívidos e perceptualmente consistentes porque foi projetada em torno da visão humana. Os gradientes em OKLCH permanecem saturados e uniformemente brilhantes em todo o seu intervalo.
  • Use in oklch em qualquer gradiente: linear-gradient(in oklch to right, red, blue). Use color-mix(in oklch, color1 50%, color2) para mistura programática.
  • O Conversor de Cores permite converter valores HEX ou RGB para OKLCH para que você possa entender como suas cores irão interpolar antes de se comprometer com um design de gradiente.
  • O Gerador de Gradientes permite visualizar como diferentes espaços de cores afetam a saída do gradiente para qualquer par de cores.
  • A direção de interpolação de matiz pode ser controlada com as palavras-chave shorter hue, longer hue, increasing hue e decreasing hue — úteis para efeitos arco-íris e controle preciso de gradiente com múltiplas paradas.

Cores relacionadas

Marcas relacionadas

Ferramentas relacionadas