Guía detallada

Color Contrast Optimization Guide

Ver contenido

Optimización de Contraste de Color: Cumpliendo Estándares WCAG AA y AAA

Introducción

El contraste de color es fundamental para la accesibilidad web, afectando si los usuarios pueden percibir e interactuar con tu contenido. Esta guía completa cubre los requisitos técnicos para cumplimiento WCAG, metodologías de testing, estrategias de diseño y patrones de implementación para lograr estándares de contraste Nivel AA y AAA.

Entendiendo los Requisitos de Contraste

Matriz de Contraste WCAG

Tipo de Contenido Nivel AA Nivel AAA Criterio WCAG
Texto normal 4.5:1 7:1 1.4.3 / 1.4.6
Texto grande (≥18pt/14pt negrita) 3:1 4.5:1 1.4.3 / 1.4.6
Componentes UI 3:1 N/A 1.4.11
Objetos gráficos 3:1 N/A 1.4.11
Indicadores de foco 3:1 N/A 1.4.11
Subrayados de enlaces 3:1 N/A 1.4.1

La Fórmula de Contraste

La relación de contraste se calcula usando luminancia relativa:

Relación de Contraste = (L1 + 0.05) / (L2 + 0.05)

Donde:
L1 = Luminancia relativa del color más claro
L2 = Luminancia relativa del color más oscuro

Luminancia Relativa = 0.2126 * R + 0.7152 * G + 0.0722 * B

Para cada componente RGB:
Si sRGB ≤ 0.04045: valor = sRGB / 12.92
Si sRGB > 0.04045: valor = ((sRGB + 0.055) / 1.055) ^ 2.4

Nota: Usa herramientas automatizadas en lugar de cálculo manual.

Herramientas de Testing

DevTools del Navegador

Chrome DevTools:
1. Inspeccionar elemento
2. Click en muestra de color en panel Estilos
3. Ver sección "Contrast ratio"
4. Ver estado de cumplimiento AA/AAA

Herramientas de Línea de Comandos

# Usando Pa11y para verificación de contraste
npx pa11y https://ejemplo.com --include-notices --include-warnings

# Usando axe-cli
npx @axe-core/cli https://ejemplo.com

Testing Automatizado

// Cypress con axe-core
import 'cypress-axe';

describe('Tests de Contraste', () => {
  beforeEach(() => {
    cy.visit('/');
    cy.injectAxe();
  });

  it('no debe tener violaciones de contraste', () => {
    cy.checkA11y(null, {
      rules: {
        'color-contrast': { enabled: true }
      }
    });
  });
});

Plugins de Herramientas de Diseño

Herramienta Plugin Características
Figma Stark Simulación daltonismo, verificación contraste
Figma A11y - Color Contrast Relación de contraste en tiempo real
Sketch Stark Igual que versión Figma
Adobe XD Color Contrast Analyzer Verificador de contraste integrado

Violaciones Comunes y Correcciones

Problemas de Contraste de Texto

Problema: Texto Gris Claro

/* FALLA AA - relación 2.85:1 */
.texto-atenuado {
  color: #999999;
  background-color: #ffffff;
}

/* PASA AA - relación 4.54:1 */
.texto-atenuado {
  color: #767676;
  background-color: #ffffff;
}

/* PASA AAA - relación 7.0:1 */
.texto-atenuado {
  color: #595959;
  background-color: #ffffff;
}

Problema: Texto Placeholder

/* FALLA - Placeholders predeterminados a menudo tienen bajo contraste */
input::placeholder {
  color: #c0c0c0; /* 1.9:1 */
}

/* PASA AA - Placeholder mejorado */
input::placeholder {
  color: #757575; /* 4.6:1 */
}

/* Alternativa: Usar etiquetas visibles en lugar de placeholders */

Problema: Texto Coloreado sobre Fondo Coloreado

/* FALLA - Azul sobre azul claro: 2.1:1 */
.aviso {
  color: #4a90d9;
  background-color: #e3f2fd;
}

/* PASA AA - Azul más oscuro: 4.6:1 */
.aviso {
  color: #1565c0;
  background-color: #e3f2fd;
}

Contraste de Componentes UI (WCAG 1.4.11)

Botones

/* FALLA - Borde de botón muy claro */
.btn-outline {
  border: 1px solid #cccccc; /* 1.6:1 contra blanco */
  color: #333333;
  background: transparent;
}

/* PASA - Contraste de borde suficiente */
.btn-outline {
  border: 2px solid #767676; /* 4.5:1 contra blanco */
  color: #333333;
  background: transparent;
}

Campos de Formulario

/* FALLA - Bordes de input se mezclan con fondo */
input {
  border: 1px solid #e0e0e0; /* 1.4:1 */
  background: #ffffff;
}

/* PASA - Límites de input visibles */
input {
  border: 1px solid #767676; /* 4.5:1 */
  background: #ffffff;
}

/* Alternativa: Usar diferencia de color de fondo */
input {
  border: 1px solid #e0e0e0;
  background: #f5f5f5; /* Crea límite visual */
}

Indicadores de Foco

/* FALLA - Visibilidad de foco insuficiente */
:focus {
  outline: 1px solid #cccccc;
}

/* PASA - Indicador de foco claro */
:focus {
  outline: 2px solid #005fcc;
  outline-offset: 2px;
}

/* Mejorado: Múltiples señales visuales */
:focus {
  outline: 3px solid #005fcc;
  outline-offset: 2px;
  box-shadow: 0 0 0 4px rgba(0, 95, 204, 0.2);
}

Enlaces

/* FALLA - Enlaces distinguidos solo por color */
a {
  color: #0066cc;
  text-decoration: none;
}

/* PASA - Indicador visual adicional */
a {
  color: #0066cc;
  text-decoration: underline;
}

/* Alternativa: Otras señales visuales */
a {
  color: #0066cc;
  text-decoration: none;
  border-bottom: 1px solid currentColor;
}

a:hover,
a:focus {
  text-decoration: underline;
}

Estrategias de Diseño

Creando Paletas de Color Accesibles

// Colores base con variantes seguras para contraste
$colors: (
  primary: (
    50: #e3f2fd,   // Fondo
    500: #2196f3,  // Solo decorativo
    700: #1565c0,  // Texto sobre blanco (4.6:1)
    900: #0d47a1   // Texto sobre blanco (8.0:1)
  ),
  gray: (
    100: #f5f5f5,  // Fondo claro
    500: #9e9e9e,  // Solo decorativo
    600: #757575,  // Texto sobre blanco (4.6:1)
    900: #212121   // Texto alto contraste
  )
);

Diseño Amigable para Daltonismo

/* No dependas solo del color */

/* MAL: Error indicado solo por color rojo */
.error {
  color: red;
}

/* BIEN: Múltiples indicadores */
.error {
  color: #c62828;
  font-weight: bold;
}
.error::before {
  content: "⚠ ";
}

/* O usa íconos */
.mensaje-error {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  color: #c62828;
}
.mensaje-error svg {
  flex-shrink: 0;
}

Consideraciones de Modo Oscuro

/* Modo claro */
:root {
  --text-primary: #212121;    /* 15.4:1 sobre blanco */
  --text-secondary: #757575;  /* 4.6:1 sobre blanco */
  --background: #ffffff;
  --surface: #f5f5f5;
}

/* Modo oscuro */
@media (prefers-color-scheme: dark) {
  :root {
    --text-primary: #e0e0e0;    /* 12.6:1 sobre fondo oscuro */
    --text-secondary: #9e9e9e;  /* 5.0:1 sobre fondo oscuro */
    --background: #121212;
    --surface: #1e1e1e;
  }
}

/* Aplicar consistentemente */
body {
  color: var(--text-primary);
  background-color: var(--background);
}

Degradados e Imágenes

/* Asegurar que el texto sobre degradados/imágenes permanezca legible */

/* Opción 1: Overlay */
.hero-text {
  position: relative;
  z-index: 1;
}
.hero::before {
  content: '';
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.5);
  z-index: 0;
}

/* Opción 2: Sombra de texto */
.hero-text {
  color: #ffffff;
  text-shadow:
    0 1px 2px rgba(0, 0, 0, 0.8),
    0 0 20px rgba(0, 0, 0, 0.5);
}

/* Opción 3: Fondo detrás del texto */
.hero-text {
  background: rgba(0, 0, 0, 0.7);
  padding: 1rem 2rem;
  color: #ffffff;
}

Patrones de Implementación

Propiedades Personalizadas CSS para Tematización

:root {
  /* Sistema de colores seguro para contraste */
  --color-text: hsl(0, 0%, 13%);           /* #212121 */
  --color-text-muted: hsl(0, 0%, 46%);     /* #757575 */
  --color-background: hsl(0, 0%, 100%);    /* #ffffff */
  --color-border: hsl(0, 0%, 46%);         /* #757575 */
  --color-primary: hsl(210, 79%, 46%);     /* #1976d2 */
  --color-primary-text: hsl(210, 79%, 35%);/* Para uso en texto */
  --color-focus: hsl(210, 100%, 40%);      /* #005fcc */
}

/* Uso */
body {
  color: var(--color-text);
  background: var(--color-background);
}

.link {
  color: var(--color-primary-text);
}

.border {
  border: 1px solid var(--color-border);
}

:focus-visible {
  outline: 2px solid var(--color-focus);
}

Verificaciones CI/CD Automatizadas

# Workflow de GitHub Actions
name: Tests de Accesibilidad
on: [push, pull_request]

jobs:
  a11y:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Instalar dependencias
        run: npm ci

      - name: Build
        run: npm run build

      - name: Ejecutar Pa11y
        run: |
          npx pa11y-ci --config .pa11yci.json

# .pa11yci.json
{
  "defaults": {
    "standard": "WCAG2AA",
    "runners": ["axe"],
    "threshold": 0
  },
  "urls": [
    "http://localhost:3000/",
    "http://localhost:3000/productos",
    "http://localhost:3000/contacto"
  ]
}

Documentación del Sistema de Diseño

## Guías de Contraste de Color

### Colores de Texto

| Uso | Color | Hex | Fondo Mín | Relación |
|-----|-------|-----|-----------|----------|
| Texto primario | Gray 900 | #212121 | Blanco | 15.4:1 |
| Texto secundario | Gray 600 | #757575 | Blanco | 4.6:1 |
| Enlaces | Blue 700 | #1565c0 | Blanco | 4.6:1 |

### Hacer y No Hacer

✅ HACER:
- Usar Gray 600 (#757575) o más oscuro para texto
- Agregar subrayados a enlaces
- Probar todas las combinaciones de colores

❌ NO HACER:
- Usar colores más claros que Gray 600 para texto
- Depender solo del color para significado
- Usar texto placeholder como etiquetas

Monitoreo y Mantenimiento

Checklist de Auditoría de Contraste

## Auditoría Mensual de Contraste

- [ ] Ejecutar escaneo automatizado (axe, Pa11y)
- [ ] Verificar nuevas páginas/componentes
- [ ] Verificar contraste en modo oscuro
- [ ] Probar en dispositivos móviles reales
- [ ] Revisar colores del sistema de diseño
- [ ] Verificar embeds de terceros

Manejando Casos Especiales

/* Estados deshabilitados - exentos de requisitos de contraste */
.button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* Texto decorativo - exento si es puramente estético */
.watermark {
  /* No necesita cumplir contraste si no es esencial */
}

/* Logos - exentos de requisitos de contraste */
.logo {
  /* Logos de marca no necesitan cumplir contraste */
}

Referencia Rápida

Combinaciones de Colores Seguras

Fondo Colores de Texto Seguros
#ffffff (blanco) #767676 o más oscuro (4.5:1+)
#f5f5f5 (gray 100) #616161 o más oscuro (4.5:1+)
#000000 (negro) #949494 o más claro (4.5:1+)
#1565c0 (blue 700) #ffffff (4.6:1)

Artículos Relacionados


Referencias

  1. W3C - WCAG 2.2 SC 1.4.3 Contraste (Mínimo)
  2. W3C - WCAG 2.2 SC 1.4.11 Contraste No Textual
  3. WebAIM - Contraste y Accesibilidad del Color
  4. Deque - Analizador de Contraste de Color
  5. A11Y Project - Contraste de Color

Artículos relacionados

Versión relacionada

Introducción

Color Contrast Explained

El contraste de color es la diferencia en luminancia entre el primer plano (texto) y los colores de fondo

Hub de categoría

Hub

Wcag Compliance Hub

La accesibilidad web asegura que los sitios web y aplicaciones puedan ser utilizados por todos, incluyendo personas con discapacidades