Conversor de cores e verificador de contraste
Converte entre HEX, RGB, HSL, OKLCH e os nomes de cor do CSS, e verifica a relação de contraste WCAG entre duas cores.
- HEX
#3b82f6 - RGB
rgb(59, 130, 246) - HSL
hsl(217, 91.2%, 59.8%) - OKLCH
oklch(62.31% 0.188 259.81) - NomeSem nome CSS exato
- HEX
#ffffff - RGB
rgb(255, 255, 255) - HSL
hsl(0, 0%, 100%) - OKLCH
oklch(100% 0 0) - Nome
white
É para texto corrido deste tamanho que o limiar de 4.5:1 foi escrito.
O texto grande só precisa de 3:1
O que esta ferramenta faz
Duas tarefas que acabam sempre por ser uma. Tem uma cor e precisa dela noutra notação: o ficheiro de design diz uma coisa e a folha de estilos quer outra. E tem duas cores e precisa de saber se um texto da primeira se lê sobre a segunda. Por isso esta página recebe duas cores, mostra cada uma em todos os formatos ao mesmo tempo e mede o contraste entre elas.
Tudo corre no seu navegador. Nada de uma paleta de marca que ainda não foi lançada precisa de viajar até um servidor para ser convertido.
As cinco notações
Qualquer uma delas pode ser colada, e todas voltam a sair:
- Hexadecimal — três, quatro, seis ou oito dígitos. As formas curtas duplicam cada dígito, por isso #f0a significa #ff00aa. Quatro e oito dígitos levam o alfa na última posição.
- RGB — os três canais como números ou percentagens. São aceites tanto rgb(59, 130, 246) como rgb(59 130 246 / 50%); a forma com vírgulas é a que esta ferramenta escreve de volta, porque continua a ser a que a maior parte do código à sua volta usa.
- HSL — matiz em graus, depois saturação e luminosidade em percentagem. Os matizes dão a volta, por isso 480 e -120 são válidos e valem 120 e 240.
- OKLCH — luminosidade, croma e matiz num espaço percetualmente uniforme. A luminosidade pode escrever-se 62.8% ou 0.628.
- Nomes CSS — os 148, incluindo rebeccapurple e as duas grafias de cada cinzento. Um nome só aparece na saída quando a correspondência é exata.
Uma particularidade que vale a pena conhecer: hexadecimal, RGB e OKLCH sobrevivem intactos a uma ida e volta, mas o HSL não bem. É impresso com a precisão que as pessoas realmente leem — graus inteiros, uma casa decimal de percentagem — e isso não chega para endereçar os 16,7 milhões de cores sRGB. Converta um hexadecimal para HSL e de volta e um canal pode mexer-se uma unidade. A alternativa seria uma saída como hsl(217.22, 91.19%, 59.8%), que ninguém quer colar. O erro fica muito abaixo do que o olho consegue ver.
Porque existe o OKLCH
O HSL parece descrever a luminosidade, e não descreve. O seu número de luminosidade é uma propriedade dos números, não da luz. O amarelo puro e o azul puro têm ambos 50% de luminosidade em HSL:
amarelo #ffff00 hsl 50% oklch 96.8% azul #0000ff hsl 50% oklch 45.2%
Qualquer pessoa vê que o amarelo é o mais claro dos dois, e o OKLCH di-lo. Isto não é académico: é a razão pela qual uma paleta construída mantendo a luminosidade HSL constante e rodando o matiz produz um conjunto de cores de aspeto desesperadamente irregular, e pela qual o mesmo truque em OKLCH produz um conjunto que parece uma família. É também a razão pela qual, em OKLCH, duas cores com a mesma luminosidade costumam ter um contraste parecido sobre o mesmo fundo — coisa que o HSL não pode prometer de todo.
Os outros dois números são o croma — grosso modo, o quão colorido, a partir de 0 para o cinzento — e o matiz em graus. Ao contrário da saturação do HSL, o croma não é uma percentagem de nada, e é por isso que o valor máximo utilizável depende tanto da luminosidade como do matiz.
Quando uma cor não pode ser mostrada
O OKLCH consegue descrever mais cores do que um ecrã comum consegue produzir. Peça uma luminosidade de 70% com um croma de 0.4 e nomeou um verde que existe em princípio e em lado nenhum do sRGB. A ferramenta limita essa cor ao intervalo e marca-a como fora do sRGB, em vez de lhe devolver em silêncio outra coisa.
O aviso só aparece quando o limite muda de facto a cor que obtém. Esta distinção pesa mais do que parece. O vermelho sRGB fica exatamente na fronteira do gamut, por isso um valor OKLCH publicado para ele, arredondado a quatro casas decimais, cai tecnicamente um fio de cabelo lá fora — cerca de duas partes em dez mil, que caem no mesmo byte e são invisíveis. Avisar sobre isso ensinar-lhe-ia a ignorar o aviso. Uma cor de uma paleta de gamut largo falha por passos inteiros: o blue-500 do Tailwind v4 pede 261 de um máximo de 255 no canal azul, e num ecrã sRGB não é mesmo a cor pedida.
O contraste e os seus três limiares
A relação de contraste compara a luminância relativa de duas cores. Vai de 1:1 para duas cores iguais até 21:1 para preto sobre branco, e nada consegue ultrapassar isso. As WCAG 2.1 fixam três limiares, e não são intermutáveis:
- 4.5:1 para o texto corrido — tudo abaixo de 18pt, ou abaixo de 14pt a negrito. É este que as pessoas querem dizer quando afirmam que uma cor «chumba no contraste».
- 3:1 para o texto grande — 18pt ou mais, ou 14pt a negrito ou mais. As letras maiores transportam mais sinal por si próprias, por isso a fasquia desce.
- 3:1 para controlos e gráficos — o contorno de um campo, a seta de uma lista, as barras de um gráfico. Acrescentado nas WCAG 2.1 e amplamente esquecido, porque as pessoas verificam o seu texto e nunca a caixa à volta dele.
O nível AAA sobe os dois primeiros para 7:1 e 4.5:1. Vale a pena procurá-lo no texto corrido e é genuinamente difícil de atingir com uma paleta de marca; AA é o que a regulamentação e as auditorias pedem.
Os tamanhos nessas regras são pontos CSS, não pixels: 18pt são 24px e 14pt cerca de 18,7px com as predefinições. É fácil supor que um título de 20px conta como texto grande. Não conta.
Cores translúcidas
Texto semitransparente sobre um fundo sólido tem uma relação de contraste perfeitamente definida: o navegador mistura as duas cores antes de pintar, e esta ferramenta também. Texto cinzento a 60% de opacidade é simplesmente um cinzento mais claro assim que assenta, e é medido como aquilo em que assenta. As ferramentas que ignoram o canal alfa comunicam a relação da cor que escreveu e não da que qualquer pessoa vê, o que a exagera sempre — um verificador de acessibilidade que erra a seu favor é pior do que nenhum.
Um fundo translúcido é outra situação, e a ferramenta recusa-a. O que se vê através depende do que estiver por baixo, e essa não é uma pergunta a que as duas cores desta página possam responder. Resolva o fundo na cor em que ele realmente se compõe e meça essa.
O que a relação não lhe diz
Uma relação que passa é um chão, não um veredicto. Três coisas que não cobre:
- O daltonismo. Um vermelho e um verde de luminância idêntica têm uma relação próxima de 1:1 e são indistinguíveis para toda a gente — mas duas cores podem passar a relação e continuar a ser a única coisa que separa dois estados, o que falha para quem não as distingue. Nunca ponha o significado apenas no matiz.
- Os tipos finos. A fórmula não sabe nada sobre a espessura do traço. Um peso capilar a 4.5:1 pode custar mais a ler do que um peso normal a 4:1.
- A própria fórmula. Sabe-se que o contraste das WCAG 2 é pouco simpático para texto claro sobre fundo escuro, comunicando relações que parecem mais altas do que se leem. A APCA, redigida para as WCAG 3, modela isto melhor — mas não é normativa, nenhuma auditoria a aceita ainda, e mostrar duas pontuações em contradição não ajudaria ninguém. Daí ser discutida aqui e não impressa acima.
Uma nota de implementação para quem compare resultados com o seu próprio código: a fórmula da luminância usa um limiar de 0.03928, ligeiramente diferente do 0.04045 da definição atual de sRGB. As WCAG citam o valor antigo, por isso é esse o usado aqui. Seguir a especificação pesa mais do que a coerência interna, e a diferença nunca transforma um passa num chumba.
Perguntas frequentes
- Porque é que o meu hexadecimal muda depois de uma ida e volta em HSL?
- Porque o HSL é impresso com uma precisão que as pessoas conseguem ler e voltar a escrever, e essa não chega para nomear todas as cores sRGB. Mexe-se no máximo um passo por canal, o que é invisível. Hexadecimal, RGB e OKLCH vão e voltam exatos, por isso use um desses se precisar de um passo intermédio sem perdas.
- O que significa «Fora do sRGB»?
- O valor OKLCH que introduziu nomeia uma cor que o seu ecrã não consegue produzir, por isso foi limitada à mais próxima que consegue. Os valores tirados de paletas de gamut largo como o Tailwind v4 fazem isto com frequência. O aviso só aparece quando o limite muda a cor apresentada, pelo que um valor arredondado que continue a cair no mesmo byte não o dispara.
- O meu texto cumpre AA. É acessível?
- Ultrapassa uma fasquia específica. A relação não diz nada sobre se a cor é a única coisa que distingue dois estados, sobre a espessura do traço, nem sobre como a combinação se lê para alguém com baixa visão. Trate um cumprimento como o início da verificação, não o seu fim.
- Porque é que o meu título de 20px não é texto grande?
- A regra está escrita em pontos, não em pixels: 18pt são 24px, e 14pt a negrito cerca de 18,7px. Um título normal de 20px fica abaixo da linha e é medido face a 4.5:1 como qualquer outro texto corrido.
- Posso verificar o contraste de um fundo semitransparente?
- Não a partir de duas cores apenas: a resposta depende do que estiver atrás, e a página não o sabe. Calcule a cor em que o fundo se compõe e introduza-a. Já um primeiro plano semitransparente funciona e é tratado corretamente: é composto sobre o fundo antes da medição, exatamente como o navegador o pinta.
- A minha paleta é enviada para algum lado?
- Não. A análise, a conversão e o cálculo do contraste correm todos no seu navegador; nada do que escrever sai do seu dispositivo.