Verificador de contraste de cores (WCAG)

Este verificador calcula a razão de contraste entre a cor do texto e a do fundo, de 1:1 a 21:1, e diz se ela passa nos níveis AA e AAA da WCAG 2.2, para texto normal, texto grande e elementos gráficos. Quando a combinação não passa, ele sugere uma versão da cor do texto, no mesmo tom, que alcança o AA ou o AAA.

Atualizado em · Por Leonardo Gaertner

Texto normal: o rápido cachorro marrom pula sobre a cerca.

Texto grande, 24px ou 18,66px em negrito

5,32:1
  • AA texto normal (4,5)
  • AA texto grande (3)
  • AAA texto normal (7)
  • AAA texto grande (4,5)
  • Ícones e bordas (3)

Achou um resultado errado ou tem uma sugestão? Avise por e-mail.

Como usar

  1. Digite ou escolha a cor do texto e a cor do fundo.
  2. Veja a razão de contraste, a prévia e quais níveis a combinação alcança.
  3. Se não passar, clique em uma das sugestões para aplicar a cor ajustada.

Como funciona

A razão de contraste compara a luminância relativa das duas cores: (L1 + 0,05) ÷ (L2 + 0,05), em que L1 é a da cor mais clara. A luminância considera que o olho é mais sensível ao verde que ao vermelho e ao azul: L = 0,2126 R + 0,7152 G + 0,0722 B, com cada canal convertido para luz linear antes.

A WCAG pede no mínimo 4,5:1 para texto normal e 3:1 para texto grande (a partir de 24px, ou 18,66px em negrito) no nível AA, e 7:1 e 4,5:1 no AAA. Ícones, bordas de campos e outros elementos gráficos precisam de 3:1. O limite é exato: 4,49:1 não passa no AA, por isso a ferramenta mostra a razão sem arredondar para cima.

Exemplo

Texto #777777 sobre fundo #ffffff: 4,47:1

Passa no AA para texto grande, não passa para texto normal

Sugestão para o AA: um cinza um pouco mais escuro

Fonte: W3C: WCAG 2.2, critério 1.4.3 (contraste mínimo); W3C: definição de luminância relativa e razão de contraste

Em código

Para calcular o contraste da WCAG em código, converta cada canal para luz linear, calcule a luminância das duas cores e divida a maior pela menor, somando 0,05 em cada uma.

JavaScript
// Razão de contraste da WCAG 2 entre duas cores em HEX ("#777777" e "#ffffff")
function luminancia(hex) {
  const n = parseInt(hex.replace('#', ''), 16);
  const [r, g, b] = [(n >> 16) & 255, (n >> 8) & 255, n & 255].map((v) => {
    const c = v / 255;
    return c <= 0.04045 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4; // canal em luz linear
  });
  return 0.2126 * r + 0.7152 * g + 0.0722 * b;
}

function contraste(cor1, cor2) {
  const [clara, escura] = [luminancia(cor1), luminancia(cor2)].sort((a, b) => b - a);
  return (clara + 0.05) / (escura + 0.05);
}

const r = contraste('#777777', '#ffffff');
console.log(r.toFixed(2), r >= 4.5 ? 'passa no AA' : 'não passa no AA'); // 4.48 não passa no AA (a razão exata é 4,478...)
Python
def luminancia(cor: str) -> float:
    """Luminância relativa da WCAG 2 de uma cor em HEX de 6 dígitos."""
    h = cor.lstrip("#")
    canais = []
    for i in (0, 2, 4):
        c = int(h[i : i + 2], 16) / 255
        canais.append(c / 12.92 if c <= 0.04045 else ((c + 0.055) / 1.055) ** 2.4)
    r, g, b = canais
    return 0.2126 * r + 0.7152 * g + 0.0722 * b


def contraste(cor1: str, cor2: str) -> float:
    clara, escura = sorted((luminancia(cor1), luminancia(cor2)), reverse=True)
    return (clara + 0.05) / (escura + 0.05)


r = contraste("#777777", "#ffffff")
print(f"{r:.2f}", "passa no AA" if r >= 4.5 else "não passa no AA")  # 4.48 não passa no AA (a razão exata é 4,478...)
PHP
<?php
// Luminância relativa da WCAG 2 de uma cor em HEX de 6 dígitos
function luminancia(string $cor): float
{
    [$r, $g, $b] = array_map(function (string $par): float {
        $c = hexdec($par) / 255;
        return $c <= 0.04045 ? $c / 12.92 : (($c + 0.055) / 1.055) ** 2.4;
    }, str_split(ltrim($cor, '#'), 2));
    return 0.2126 * $r + 0.7152 * $g + 0.0722 * $b;
}

function contraste(string $cor1, string $cor2): float
{
    $l = [luminancia($cor1), luminancia($cor2)];
    return (max($l) + 0.05) / (min($l) + 0.05);
}

$r = contraste('#777777', '#ffffff');
printf("%.2f %s\n", $r, $r >= 4.5 ? 'passa no AA' : 'não passa no AA'); // 4.48 não passa no AA (a razão exata é 4,478...)

Perguntas frequentes

O que é texto grande para a WCAG?

Texto de pelo menos 18 pontos (24px) ou de 14 pontos (18,66px) em negrito. Abaixo disso, vale o limite de texto normal: 4,5:1 no AA.

Logotipos e textos decorativos precisam de contraste?

Não. A WCAG isenta logotipos, textos que fazem parte de uma imagem sem função e elementos desabilitados. Textos em botões, links e campos precisam.

Como calcular o contraste em código?

Converta cada canal para luz linear, calcule a luminância das duas cores e aplique a razão. A seção Em código, nesta página, mostra a função em JavaScript, Python e PHP, com o mesmo cálculo desta ferramenta. Na hora de exibir, não arredonde para cima: 4,478 aparece como 4,48 com arredondamento comum, mas não chega a 4,5.

E o APCA, da WCAG 3?

O APCA é um método mais novo, que leva em conta o tamanho e o peso da fonte, e está em discussão para a WCAG 3, que ainda não é norma. As leis e auditorias de acessibilidade, inclusive no Brasil, seguem a WCAG 2, que é o que esta ferramenta calcula.