Bhinish Dhiman
Contraste no modo escuro: por que o WCAG 2 engana você
Traduzido do original em inglês. Ler o original
O WCAG 2 soma uma constante fixa de 0.05 aos dois valores de luminância. Perto do preto, essa constante domina a razão, então pares do modo escuro podem passar com folga e ainda assim parecer apagados. Verifique temas escuros com o APCA e conte com a necessidade de uma variante mais clara de cada cor da marca.
Uma paleta que passa em todas as verificações sobre branco não vai passar automaticamente quando você a inverter. Pior: a ferramenta padrão muitas vezes vai dizer que passou.
De onde vem o problema
A fórmula de contraste do WCAG 2 é:
(L1 + 0.05) / (L2 + 0.05)
em que L1 e L2 são as luminâncias relativas da cor mais clara e da mais escura. Esse 0.05 modela o reflexo ambiente na tela, a luz que reflete no display e nunca some por completo, de modo que nada na tela tem luminância realmente zero.
É uma simplificação razoável, e no lado claro da faixa ela quase não pesa. Uma luminância de 0.9 mais 0.05 é um ajuste de 5%.
No lado escuro, ela domina por completo. Um cinza muito escuro pode ter luminância de 0.008. Somar 0.05 a leva para 0.058, e a constante passa a ser sete vezes maior do que a medida real. A fórmula deixou de descrever as cores e passou a descrever a constante.
A consequência prática: pequenas diferenças de luminância entre cores escuras são infladas em razões que parecem grandes. Dois cinzas escuros realmente difíceis de distinguir podem passar com folga.
Como isso aparece na prática
O erro típico do modo escuro é pegar uma cor da marca que funciona sobre branco e usá-la sem mudança num fundo escuro.
Pegue um azul médio como #2563eb. Sobre branco, ele dá cerca de 5.17:1, uma aprovação AA limpa para texto de corpo. Coloque-o sobre um quase preto #0c0f15 e o WCAG 2 dá mais ou menos 3.6:1. Fica abaixo do AA para texto de corpo, então esse você pegaria.
Mas clareie a cor um pouco e você pode chegar a 4.5:1 enquanto o texto continua parecendo apagado e vibrando levemente contra o fundo escuro. A razão diz que passa. Os seus olhos dizem outra coisa. E, num fundo escuro, a penalidade perceptual por ficar no limite é muito mais dura do que sobre branco.
Esbarramos exatamente nisso ao construir o nosso próprio site. A cor de link do nosso modo escuro passava no WCAG AA com folga e, quando a testamos no APCA, deu Lc 37 contra uma exigência de 75. Parecia ótima num print e era realmente difícil de ler.
O APCA trata a polaridade direito
O APCA produz um valor com sinal. Positivo significa texto escuro sobre fundo claro; negativo, texto claro sobre fundo escuro. Ele usa curvas diferentes para cada direção, porque a resposta perceptual é de fato assimétrica: texto claro sobre um fundo escuro parece vazar para fora e ganhar peso aparente, um efeito que não acontece no sentido inverso.
É por isso que o APCA é o número mais confiável especificamente no modo escuro. Ele foi projetado levando essa assimetria em conta, enquanto o WCAG 2 trata as duas direções com a mesma aritmética.
O que fazer
Dê duas variantes a cada cor da marca. Uma escurecida para fundos claros, outra clareada para fundos escuros. Mesmo matiz, mesmo croma, dois valores de luminosidade. É a mudança estrutural mais útil que existe, e é o que publicar nos dois temas realmente exige. Uma única cor não serve para os dois.
Não use preto puro como fundo escuro. #000000 maximiza a distorção do reflexo e produz um halo desconfortável com texto claro. Algo na faixa de #0c0f15 a #16181d é mais fácil de ler e deixa espaço para montar uma escala de elevação.
Também não use texto branco puro. Branco em brilho máximo sobre quase preto é agressivo e causa um brilho espalhado visível em tamanhos pequenos. Um branco levemente quente na região de #e8ecf2 é mais confortável de ler e mede quase igual.
Reduza a saturação conforme a cor fica mais clara. Cores muito saturadas sobre fundos escuros vibram. Baixar o croma conforme você aumenta a luminosidade produz um resultado mais calmo, que mede o mesmo.
Verifique o modo escuro no tamanho e no peso reais. A distância entre os dois modelos aumenta conforme o texto diminui, então um rótulo de 14px no modo escuro é o pior caso nos dois eixos ao mesmo tempo.
Acertando as variantes
A abordagem eficiente é manter matiz e croma e mexer só na luminosidade, porque é a luminosidade que determina o contraste e é o matiz que carrega a sua marca. Trabalhe em OKLCH, em que a luminosidade é perceptualmente uniforme, então passos iguais parecem iguais.
Isso dá um padrão de dois tokens:
--brand: oklch(55% 0.16 255);
--brand-on-light: oklch(48% 0.16 255);
--brand-on-dark: oklch(78% 0.12 255);
Repare na queda de croma da variante escura. É o ponto da dessaturação acima, colocado em prática.
O nosso verificador de contraste mostra o WCAG 2 e o APCA juntos e avisa quando eles discordam, o que, em fundos escuros, acontece com frequência. A faixa de luminosidade mostra quais trechos do seu matiz passam contra um determinado fundo, para que você escolha as duas variantes no mesmo eixo.