Contraste insuficiente é a falha de acessibilidade mais comum na web — presente em 96,3% das páginas auditadas pelo WebAIM no relatório anual de acessibilidade. E o Tailwind CSS torna esse erro muito fácil de cometer.
O problema
O Tailwind tem dezenas de variações de cor por escala (gray-100, gray-200, gray-300...). A maioria dos devs escolhe pela aparência visual na tela, mas aparência não garante contraste suficiente para pessoas com baixa visão ou daltonismo.
O WCAG 2.1 define dois critérios:
- 1.4.3 — Nível AA: taxa de contraste mínima de 4,5:1 para texto normal, 3:1 para texto grande (≥18pt/24px ou ≥14pt/18,7px em negrito)
- 1.4.6 — Nível AAA: taxa mínima de 7:1 para texto normal
Uma única falha nível A ou AA significa que o site não pode declarar conformidade com nenhum nível WCAG.
Como verificar o contraste
Antes de corrigir, você precisa medir. Três formas:
1. Web para Todos (automatizado): cole a URL no analisador e filtre por "contraste" nos resultados. O diagnóstico aponta o elemento exato com a taxa calculada.
2. Firefox DevTools: abra o inspetor, clique em um elemento de texto, veja o painel Acessibilidade — ele mostra a taxa de contraste em tempo real.
3. Calculadora manual: use a calculadora de contraste do WebAIM com o hex da cor do texto e do fundo.
A tabela de contraste do Tailwind
A escala padrão do Tailwind sobre fundo branco (#FFFFFF):
| Classe Tailwind | Hex | Contraste | WCAG AA | WCAG AAA |
|---|---|---|---|---|
gray-900 | #111827 | 19,3:1 | ✅ | ✅ |
gray-800 | #1F2937 | 14,0:1 | ✅ | ✅ |
gray-700 | #374151 | 9,7:1 | ✅ | ✅ |
gray-600 | #4B5563 | 6,7:1 | ✅ | ❌ |
gray-500 | #6B7280 | 4,6:1 | ✅ | ❌ |
gray-400 | #9CA3AF | 2,9:1 | ❌ | ❌ |
gray-300 | #D1D5DB | 1,7:1 | ❌ | ❌ |
Regra prática:
gray-500é o mínimo aceitável para texto normal (AA). Para AAA, usegray-700ou mais escuro.gray-400nunca deve aparecer como cor de texto.
As correções mais comuns
Texto de placeholder e legenda
<!-- ❌ Falha AA (2,9:1) — invisível para muitos usuários -->
<input placeholder="Digite aqui" class="placeholder:text-gray-400" />
<!-- ✅ Aprovado AA (4,6:1) -->
<input placeholder="Digite aqui" class="placeholder:text-gray-500" />
Texto de ajuda abaixo de campos
<!-- ❌ Falha AA (2,9:1) -->
<p class="text-gray-400 text-sm">Máximo de 200 caracteres</p>
<!-- ✅ Aprovado AA (4,6:1) -->
<p class="text-gray-500 text-sm">Máximo de 200 caracteres</p>
<!-- ✅ Aprovado AAA (9,7:1) -->
<p class="text-gray-700 text-sm">Máximo de 200 caracteres</p>
Links sobre fundo colorido
<!-- ❌ Texto claro sobre fundo claro — falha grave -->
<div class="bg-blue-100">
<a href="#" class="text-blue-300">Saiba mais</a>
</div>
<!-- ✅ Azul escuro sobre fundo claro — contraste 7,16:1 (AAA) -->
<div class="bg-blue-50">
<a href="#" class="text-blue-800 underline hover:text-blue-900">Saiba mais</a>
</div>
Badges e rótulos de status
<!-- ❌ Amarelo sobre branco: péssimo contraste (1,3:1) -->
<span class="bg-yellow-400 text-white px-2 py-0.5 rounded text-xs">Novo</span>
<!-- ✅ Texto escuro sobre amarelo claro — contraste seguro -->
<span class="bg-yellow-100 text-yellow-800 border border-yellow-300 px-2 py-0.5 rounded text-xs">
Novo
</span>
Texto sobre fundo escuro
<!-- ❌ Cinza claro sobre azul escuro — pode falhar dependendo do tom -->
<div class="bg-blue-900">
<p class="text-blue-300">Descrição do produto</p>
</div>
<!-- ✅ Branco sobre azul escuro — alto contraste -->
<div class="bg-blue-900">
<p class="text-white">Descrição do produto</p>
</div>
A armadilha do fundo não-branco
Se o fundo não for branco puro, os valores de contraste mudam. O Tailwind slate-50 (#F8FAFC) parece branco, mas o cálculo é diferente:
<!-- Fundo slate-50 (#F8FAFC) — afeta levemente o cálculo -->
<div class="bg-slate-50">
<!-- gray-500 sobre slate-50: ~4,5:1 — verificar com calculadora -->
<p class="text-gray-500">Descrição</p>
<!-- gray-600 sobre slate-50: ~5,7:1 — aprovado AA -->
<p class="text-gray-600">Descrição com mais contraste</p>
</div>
Use sempre a calculadora com o hex real do fundo. Nunca presuma que "quase branco" é suficiente.
Configurando tokens globais no Tailwind
A melhor estratégia é definir tokens semânticos no tailwind.config.ts para evitar que cada desenvolvedor escolha a cor errada:
// tailwind.config.ts
import type { Config } from 'tailwindcss'
const config: Config = {
theme: {
extend: {
colors: {
// Textos — aprovados AAA sobre branco (#FFFFFF)
'text-primary': '#1F2937', // gray-800 — 14,0:1
'text-body': '#374151', // gray-700 — 9,7:1
'text-muted': '#6B7280', // gray-500 — 4,6:1 (mínimo AA)
// Proibidos para texto (documente isso):
// 'text-disabled': '#9CA3AF' // gray-400 — 2,9:1 — falha AA
},
},
},
}
export default config
Com tokens semânticos, o design system força o caminho correto e a revisão de PR fica mais fácil.
Checklist de contraste para o próximo deploy
- Texto principal:
gray-700ou mais escuro (AAA — 9,7:1) - Texto secundário e descrições:
gray-500no mínimo (AA — 4,6:1) - Placeholders:
gray-500no mínimo — nuncagray-400 - Links: verificar contra o fundo específico (não presuma)
- Ícones informativos: mesmo critério do texto adjacente
- Badges e tags: texto escuro sobre fundo claro ou vice-versa
- Texto sobre imagens: overlay escuro com contraste verificado
- Estados de foco: anel de foco visível (
ring-2 ring-blue-600) - Texto sobre fundos coloridos: calcular com o hex real, não pelo visual
Resultado
Corrigir contraste no Tailwind não exige redesenho. Na maioria dos casos é trocar text-gray-400 por text-gray-500, ou text-blue-300 sobre azul escuro por text-white. O impacto é direto: usuários com baixa visão, daltonismo e quem usa o celular com sol conseguem ler o conteúdo que antes estava invisível para eles.
Critérios WCAG: 1.4.3 Contraste Mínimo — Nível AA | 1.4.6 Contraste Aprimorado — Nível AAA
Verifique seu site agora: Analisador de acessibilidade gratuito do Web para Todos