XP Investimentos, Clear Corretora, XP Inc.
Numa tela de investimento, ler um número errado custa dinheiro. Por isso a cor da Clear foi construída a partir do contraste, e não conferida depois dele.
Resultado
Nas telas finais, todo texto passa no nível AAA da WCAG, a norma internacional de acessibilidade digital. O contraste é medido como uma razão entre o brilho do texto e o do fundo. 4,5:1 é o mínimo aceito e 7:1 é o nível mais alto.
Texto principal a 14,61:1, secundário a 9,21:1, etiquetas de status entre 7,09:1 e 12,62:1. Uma única exceção, declarada. Na paleta anterior, os rótulos dos gráficos ficavam perto de 3,5:1, abaixo do mínimo.
Escala
84 tons
em 7 famílias, em cada um dos dois modos
Contraste
AAA
em todo texto, com uma exceção declarada
Regularidade
2× mais
regular entre um tom e o próximo
Problema
Os rótulos de mínima e máxima do gráfico ficavam perto de 3,5:1 sobre o branco. Num app de corretora isso não é detalhe de estilo. É o preço da ação ilegível para quem enxerga pouco.
Trocar aquele cinza resolveria uma tela e mais nada, porque o problema era a escala inteira. A distância de luminosidade entre um tom e o próximo variava de 0,031 a 0,144, quase cinco vezes de diferença. Quem escolhia o tom 600 esperando um contraste recebia outro, e cada tela virava uma negociação nova.
Eram três famílias, primária, secundária e neutra, para um produto que precisa dizer alta, baixa, alerta, erro e informação.
Decisão
HSL é o padrão da indústria e erra a luminosidade. Com a mesma receita, saturação 60% e luminosidade 40%, o verde fica com 3,25:1 sobre o branco e reprova. O vermelho fica com 7,23:1 e passa no nível mais alto. O número é igual, o brilho que o olho vê não é.
Escolhi OKLCH, um modelo que descreve a cor por luminosidade, croma e matiz seguindo a percepção do olho, e não a forma como a tela emite luz. Nele, a escala deixa de ser uma coleção de cores escolhidas e vira uma função. O tom 600 tem luminosidade 0,61 nas seis famílias de cor. É medida, não aproximação.
Os passos entre um tom e o próximo passaram a variar de 0,034 a 0,081. Duas vezes mais regular que antes.
Mesma receita, dois modelos
HSLsaturação 60% · luminosidade 40%
OKLCHluminosidade 0,45
Em HSL, o mesmo número de luminosidade gera brilhos diferentes. Em OKLCH, a mesma luminosidade parece igual para o olho.
Método
Conferido no fim, o contraste vira retrabalho. Escolhe, testa, reprova, volta. Usado como ponto de partida, ele vira garantia.
Calculei a matriz cruzada de todos os pares de texto e fundo do sistema e transformei o resultado em regra de uso. Quais tons aceitam texto, quais não aceitam, e a partir de que tamanho de letra a resposta muda. Quem desenha não precisa medir. Precisa seguir.
Recorte da matriz · texto sobre fundo, modo claro
| Fundo | Fundo suave | Fundo rebaixado | Ação principal | Alta, fundo | Baixa, fundo | |
|---|---|---|---|---|---|---|
| Texto principal | 18,44 · AAA | 17,81 · AAA | 16,78 · AAA | 2,31 · reprova | 2,61 · reprova | 2,33 · reprova |
| Texto secundário | 9,50 · AAA | 9,17 · AAA | 8,64 · AAA | 1,19 · reprova | 1,34 · reprova | 1,20 · reprova |
| Texto terciário | 7,83 · AAA | 7,56 · AAA | 7,12 · AAA | 1,02 · reprova | 1,11 · reprova | 1,01 · reprova |
| Destaque | 8,00 · AAA | 7,72 · AAA | 7,28 · AAA | 1,00 · reprova | 1,13 · reprova | 1,01 · reprova |
| Alta, texto | 9,03 · AAA | 8,72 · AAA | 8,21 · AAA | 1,13 · reprova | 1,28 · reprova | 1,14 · reprova |
| Baixa, texto | 7,91 · AAA | 7,64 · AAA | 7,20 · AAA | 1,01 · reprova | 1,12 · reprova | 1,00 · reprova |
| Texto sobre cor | 1,00 · reprova | 1,04 · reprova | 1,10 · reprova | 8,00 · AAA | 7,07 · AAA | 7,91 · AAA |
Trade-off
Alta em verde e baixa em vermelho é a convenção mais forte do mercado financeiro e uma das piores para acessibilidade. É o caso clássico de daltonismo, que atinge cerca de 8% dos homens. Aqui o erro não é estético, é o saldo da pessoa.
Abandonar a convenção não era opção, porque quem opera lê a cor antes do número. A saída foi não deixar a cor sozinha. O sinal de mais ou de menos vem sempre colado no número, e no gráfico cada série ganha traço e marcador próprios.
Aqui o OKLCH se pagou. O verde e o vermelho de alta e baixa estão no mesmo tom da escala, o 800, com a mesma luminosidade, 0,45. A linha de baixa não pesa mais que a de alta sem motivo. O preço dessa escolha é que, sem o matiz, os dois viram o mesmo tom. O sinal deixou de ser detalhe e virou regra.
Texto
Preenchimento
Texto de alta a 9,03:1 e de baixa a 7,91:1 sobre o branco. O sinal vem antes do número, sempre.
Texto
Preenchimento
Simulação de deuteranopia, uma das formas de daltonismo que confundem verde e vermelho. As duas cores viram oliva e o sinal continua dizendo tudo.
Alta em linha contínua com círculos, baixa em tracejado com quadrados. Dá para ler até impresso em preto e branco.
Limite
A paleta anterior vivia na borda do que a tela consegue mostrar, entre 95% e 100% do limite do sRGB, o conjunto de cores de uma tela comum, na maioria dos tons. Cor nessa região é instável. Ela satura, perde diferença entre tons vizinhos e muda de um aparelho para outro.
A escala nova segue uma curva de croma, a intensidade da cor, que vai de 28% a 88% desse limite. Sobe até o meio da rampa e cai nas pontas. Os tons muito claros e muito escuros abrem mão de intensidade para manter a luminosidade previsível. O sistema perde alguns tons vibrantes nas extremidades e ganha o direito de ser usado por regra.
QUANTO CADA TOM USA DO LIMITE DO sRGB
Decisão
Não. Cor muito saturada sobre fundo escuro parece vibrar e sair do plano, um efeito que cansa rápido em leitura longa. Essas cores ficaram fora do modo escuro, com o sistema da Atlassian como referência de tonalidade. As superfícies escuras passaram de três para quatro níveis.
Em vez de redefinir as mesmas variáveis conforme o contexto, montei dois conjuntos completos de primitivos, as cores cruas que o sistema inteiro referencia. Um para fundo claro, outro para escuro. A alternativa deixaria o arquivo mais enxuto e quebraria a entrega para desenvolvimento, porque o Dev Mode do Figma perde o rastro de um valor que muda de significado dependendo de onde está. Arquivo menor não vale entrega pior.
Superfícies do modo escuro · antes 3, agora 4
Fundo #0D1116
Fundo suave #14171E
Elevado #1B1F26
Sobreposição #24282F
Limite
Seis séries de gráfico distinguíveis entre si a 3:1 exigiriam 3 elevado a 5, ou seja 243:1 entre os extremos. Uma tela comum oferece cerca de 21:1. Não existe paleta que resolva isso, e sistema que promete resolver está errando a conta.
A regra que ficou: cada série tem no mínimo 3:1 contra o fundo, e a diferença entre séries nunca depende só de cor. Traço, marcador e rótulo fazem o resto, como a própria norma exige.
Resultado
Um documento vivo de oito seções, do tipo que um time consulta em vez de perguntar. Propriedades, paleta, acessibilidade tipográfica, matriz de tokens no nível AAA, contraste de elementos que não são texto, aparência de foco, séries de gráfico e o guia de migração da versão anterior.
No Figma, 224 variáveis em três coleções. Primitivos com as cores cruas, semânticos com o significado de cada uso, como fundo, texto, alta e baixa, e componentes. Dois modos, claro e escuro.
A exceção declarada é o texto de exemplo (placeholder) do campo de busca, a 5,75:1. Passa no AA e não no AAA. Está documentada como exceção em vez de arredondada para cima, porque um sistema que esconde a própria exceção deixa de ser verificável.
8 seções
no documento vivo que o time consulta
224 variáveis
em 3 coleções e 2 modos no Figma
67 verificações
de contraste na paleta, nenhuma falha AAA
1 exceção
declarada, o texto de exemplo da busca a 5,75:1
Aprendizados
Quando a regra nasce da medida, ninguém precisa medir de novo. Conferir no fim só descobre o erro mais tarde.
Um 5,75:1 escrito no documento é mais confiável do que um AAA em todo lugar que ninguém consegue verificar.
Daltonismo e séries de gráfico tiveram a mesma saída, um segundo canal. Sinal, traço e marcador.
Sistema de cor e verificação de acessibilidade meus de ponta a ponta, sobre a fundação de tokens primitivos da Clear que eu havia criado no SOMA.
XP Investimentos, Clear Corretora, XP Inc.