Verificador de Contraste de Cores
Verifique a proporção de contraste WCAG AA e AAA entre cores de primeiro plano e fundo
Cor do primeiro plano (texto)
Cor de fundo
Amostra de Texto Grande (18px negrito)
Amostra de texto normal — é assim que o seu texto de corpo aparecerá sobre a cor de fundo escolhida.
Proporção de contraste
14.63:1
Conformidade WCAG
Aprovado
Normal AA
Aprovado
Normal AAA
Aprovado
Grande AA
Aprovado
Grande AAA
WCAG AA — Texto normal: 4.5:1, Texto grande (18px+ ou 14px negrito): 3:1
WCAG AAA — Texto normal: 7:1, Texto grande (18px+ ou 14px negrito): 4.5:1
O que é a Verificação de Contraste de Cores?
A verificação de contraste de cores mede a diferença de luminância entre uma cor de primeiro plano (geralmente texto) e uma cor de fundo, expressando o resultado como uma proporção. Uma proporção de 1:1 significa que as cores são idênticas; 21:1 é o máximo, representando preto sobre branco ou vice-versa. As Diretrizes de Acessibilidade para Conteúdo Web (WCAG), publicadas pelo W3C, definem proporções mínimas de contraste que o texto deve atingir para que pessoas com baixa visão ou deficiências de cor consigam lê-lo.
A fórmula da proporção de contraste vem do WCAG 2.x e se baseia na luminância relativa, uma medida do brilho aparente de uma cor ao olho humano. A luminância relativa é calculada linearizando cada canal sRGB (removendo a gama) e ponderando os canais de acordo com os coeficientes ITU-R BT.709: 0,2126 para vermelho, 0,7152 para verde e 0,0722 para azul. O verde contribui mais porque os olhos humanos são mais sensíveis à luz verde. A proporção é então (L1 + 0,05) / (L2 + 0,05), onde L1 é a luminância da cor mais clara.
O WCAG define dois níveis de conformidade. O nível AA exige uma proporção de contraste mínima de 4,5:1 para texto de tamanho normal e 3:1 para texto grande (18px ou acima, ou 14px em negrito). O nível AAA eleva a exigência para 7:1 e 4,5:1, respectivamente. O WCAG 2.1 também introduziu o Critério de Sucesso 1.4.11, que exige uma proporção de 3:1 para componentes de interface não textuais como bordas, ícones e indicadores de foco.
Por que usar este Verificador de Contraste?
Verificar o contraste a olho nu é impreciso. Cores que parecem distintas no seu monitor calibrado podem se confundir em uma tela de laptop de baixa qualidade, sob luz solar direta, ou para alguém com deuteranopia. Uma proporção numérica elimina suposições e fornece um veredicto de aprovado/reprovado em relação ao padrão WCAG.
Casos de Uso do Verificador de Contraste
Requisitos de Proporção de Contraste WCAG
A tabela abaixo resume as proporções mínimas de contraste exigidas pelo WCAG 2.1 para diferentes tipos de conteúdo e níveis de conformidade. Texto grande é definido como 18px (24 pixels CSS) ou acima em peso normal, ou 14px (18,66 pixels CSS) ou acima em peso negrito.
| Nível | Proporção mínima | Aplica-se a | Nota |
|---|---|---|---|
| AA Normal text | 4.5 : 1 | Body text, paragraphs, labels | Minimum for most UI text |
| AA Large text | 3.0 : 1 | Text >= 18px, or >= 14px bold | Minimum for headings |
| AA UI components | 3.0 : 1 | Borders, icons, focus indicators | Non-text contrast (WCAG 1.4.11) |
| AAA Normal text | 7.0 : 1 | Body text at highest standard | Enhanced readability |
| AAA Large text | 4.5 : 1 | Large text at highest standard | Enhanced for headings |
Luminância, AA e AAA Explicados
O cálculo da proporção de contraste tem três etapas: calcular a luminância de cada cor, derivar a proporção e compará-la com os limites do WCAG.
Exemplos de Código
Calcule proporções de contraste WCAG de forma programática. Cada exemplo implementa a fórmula de luminância relativa do WCAG 2.x e o cálculo da proporção de contraste. Os mesmos pares preto-sobre-branco e índigo-sobre-branco são testados para comparação.
// Calculate relative luminance per WCAG 2.x (sRGB)
function luminance(r, g, b) {
const [rs, gs, bs] = [r, g, b].map(c => {
c /= 255
return c <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4)
})
return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs
}
// Contrast ratio between two RGB colors
function contrastRatio(fg, bg) {
const l1 = luminance(...fg)
const l2 = luminance(...bg)
const lighter = Math.max(l1, l2)
const darker = Math.min(l1, l2)
return (lighter + 0.05) / (darker + 0.05)
}
contrastRatio([0, 0, 0], [255, 255, 255]) // -> 21.0
contrastRatio([99, 102, 241], [255, 255, 255]) // -> 3.95
contrastRatio([29, 78, 216], [255, 255, 255]) // -> 6.06 (AA pass)def luminance(r: int, g: int, b: int) -> float:
"""Relative luminance per WCAG 2.x, ITU-R BT.709 coefficients."""
channels = []
for c in (r, g, b):
c /= 255
channels.append(c / 12.92 if c <= 0.04045 else ((c + 0.055) / 1.055) ** 2.4)
return 0.2126 * channels[0] + 0.7152 * channels[1] + 0.0722 * channels[2]
def contrast_ratio(fg: tuple, bg: tuple) -> float:
l1 = luminance(*fg)
l2 = luminance(*bg)
lighter, darker = max(l1, l2), min(l1, l2)
return (lighter + 0.05) / (darker + 0.05)
print(f"{contrast_ratio((0, 0, 0), (255, 255, 255)):.2f}") # -> 21.00
print(f"{contrast_ratio((99, 102, 241), (255, 255, 255)):.2f}") # -> 3.95
# Check WCAG AA for normal text
ratio = contrast_ratio((29, 78, 216), (255, 255, 255))
print(f"{ratio:.2f} — {'AA pass' if ratio >= 4.5 else 'AA fail'}") # -> 6.06 — AA passpackage main
import (
"fmt"
"math"
)
func linearize(c float64) float64 {
c /= 255
if c <= 0.04045 {
return c / 12.92
}
return math.Pow((c+0.055)/1.055, 2.4)
}
func luminance(r, g, b int) float64 {
return 0.2126*linearize(float64(r)) +
0.7152*linearize(float64(g)) +
0.0722*linearize(float64(b))
}
func contrastRatio(fgR, fgG, fgB, bgR, bgG, bgB int) float64 {
l1 := luminance(fgR, fgG, fgB)
l2 := luminance(bgR, bgG, bgB)
lighter := math.Max(l1, l2)
darker := math.Min(l1, l2)
return (lighter + 0.05) / (darker + 0.05)
}
func main() {
ratio := contrastRatio(0, 0, 0, 255, 255, 255)
fmt.Printf("%.2f\n", ratio) // -> 21.00
ratio = contrastRatio(29, 78, 216, 255, 255, 255)
fmt.Printf("%.2f\n", ratio) // -> 6.06 (AA pass for normal text)
}/* WCAG-safe color pairs — tested contrast ratios */
/* 12.63:1 — passes AAA normal text */
.high-contrast {
color: #1e293b; /* slate-800 */
background: #f8fafc; /* slate-50 */
}
/* 7.07:1 — passes AAA normal text */
.dark-theme-text {
color: #e2e8f0; /* slate-200 */
background: #0f172a; /* slate-900 */
}
/* 4.57:1 — passes AA normal, fails AAA */
.accent-on-white {
color: #1d4ed8; /* blue-700 */
background: #ffffff;
}
/* 2.14:1 — fails AA for text, but passes 3:1 for large text */
.muted-heading {
color: #94a3b8; /* slate-400 */
background: #ffffff;
}