← Todos los articulos

Ciencia del color para diseñadores de interfaces: lo que aprendí al construir un sitio sin color

Las Pautas de Accesibilidad para el Contenido Web (WCAG) del W3C exigen una relación de contraste mínima de 4,5:1 para texto normal; sin embargo, una encuesta de WebAIM de 2023 descubrió que el 83,6% de los principales un millón de sitios web tenían fallas detectables de contraste WCAG 2 en sus páginas de inicio. Construí blakecrosley.com con el problema opuesto: contraste máximo (21:1) en todas partes, reduciéndolo selectivamente después.1

TL;DR

Diseñé mi sitio personal sin colores de marca. Toda la jerarquía visual opera mediante texto blanco sobre negro absoluto (#000000) en cuatro niveles de opacidad: 100%, 65%, 40% y 10%. La decisión me obligó a aprender ciencia perceptual del color — por qué sRGB miente sobre el espaciado uniforme, cómo OKLCH lo resuelve, y por qué el modo oscuro requiere relaciones de contraste diferentes al modo claro. Las herramientas interactivas a continuación le permiten explorar relaciones de contraste y diferencias entre espacios de color. La conclusión: comprender la ciencia detrás de la percepción del color produce mejores decisiones de diseño que la intuición estética.



Mi no-paleta de color

La mayoría de los sistemas de diseño comienzan con una paleta de colores. El mío comienza con la ausencia de una:

:root {
  --color-bg-dark:        #000000;
  --color-bg-elevated:    #111111;
  --color-bg-surface:     #1a1a1a;
  --color-text-primary:   #ffffff;
  --color-text-secondary: rgba(255,255,255,0.65);
  --color-text-tertiary:  rgba(255,255,255,0.4);
  --color-border:         rgba(255,255,255,0.1);
  --color-border-subtle:  rgba(255,255,255,0.05);
  --color-accent:         #ffffff;
}

Diez tokens. Sin colores de marca. Sin paleta semántica de error/éxito/advertencia. Toda la jerarquía visual opera mediante cuatro niveles de transparencia.2

Por qué funcionan cuatro niveles

Cada nivel cumple una función comunicativa específica:

Nivel Opacidad Token CSS Función Relación WCAG (sobre #000)
Primario 100% --color-text-primary Títulos, texto del cuerpo, contenido crítico 21:1 (AAA)
Secundario 65% --color-text-secondary Subtítulos, navegación, metadatos 13,7:1 (AAA)
Terciario 40% --color-text-tertiary Marcas de tiempo, texto de ayuda, estados deshabilitados 8,4:1 (AAA)
Estructural 10% --color-border Bordes, divisores, separación de fondos N/A (no es texto)

Cada nivel supera WCAG AAA (7:1) en contraste de texto. El nivel terciario al 40% de opacidad produce una relación de 8,4:1 — casi el doble del mínimo AA de 4,5:1. La elección brutalista del negro absoluto (#000000 en lugar de #0a0a0a o #1a1a1a) otorga a cada nivel de texto el máximo margen disponible.3

El incidente de --spacing-2xs

Descubrí el valor de los tokens de diseño estrictos cuando usé --spacing-2xs para el margen de un subtítulo. El token no existía en mi definición :root. El CSS falló silenciosamente, el diseño se rompió, y pasé 20 minutos depurando un problema de espaciado que debería haber sido un error en tiempo de compilación. La solución: cambiar a --spacing-xs (el token más pequeño que definí). La lección: si un valor no existe en el sistema, el diseño está mal, no el sistema.4


Por qué sRGB miente a los diseñadores

El problema de la no uniformidad perceptual

sRGB (el espacio de color estándar para la web) mapea los colores en un cubo donde cada eje (rojo, verde, azul) va de 0 a 255. Mover 50 unidades en el canal rojo no produce el mismo cambio percibido que mover 50 unidades en el canal verde. Los ojos humanos contienen más conos sensibles al verde que al rojo o azul, lo que hace que los cambios en verde sean más perceptibles que cambios equivalentes en rojo.5

La consecuencia práctica: un diseñador que crea una paleta de colores espaciando uniformemente los valores hexadecimales produce colores que se ven desigualmente espaciados. El gris “medio” entre #000000 y #FFFFFF no es #808080 (punto medio matemático) sino aproximadamente #777777 (punto medio perceptual), porque la percepción humana del brillo sigue una ley de potencia en lugar de una función lineal.6

Mi sitio evita el problema por completo. Al usar solo blanco con opacidades variables, evito la trampa de uniformidad de sRGB. La opacidad escala linealmente con la transparencia percibida sobre un fondo negro — una propiedad que la mezcla de colores sRGB no comparte.

La solución OKLCH

OKLCH (Luminosidad Oklab, Croma, Tono) es un espacio de color perceptualmente uniforme donde distancias matemáticas iguales corresponden a diferencias percibidas iguales. Un paso de 10 unidades de luminosidad siempre se ve como la misma cantidad de cambio independientemente del color inicial.7

/* sRGB: mathematically even, perceptually uneven */
--gray-100: #f5f5f5;
--gray-200: #e5e5e5;
--gray-300: #d4d4d4;

/* OKLCH: perceptually even steps */
--gray-100: oklch(96% 0 0);
--gray-200: oklch(88% 0 0);
--gray-300: oklch(80% 0 0);

El CSS moderno soporta oklch() de forma nativa. Para mi próximo proyecto que requiera una paleta de colores, definiré la paleta en OKLCH. Para mi sitio actual, el sistema basado en opacidad logra la misma uniformidad perceptual por medios diferentes.


Mi decisión sobre el modo oscuro: sin modo claro

Mi sitio no tiene media query prefers-color-scheme. Opera exclusivamente en modo oscuro. La decisión fue deliberada.8

El argumento a favor de ambos modos: Los usuarios esperan una opción de modo claro. La integración con las preferencias del sistema respeta la elección del usuario.

El argumento en contra (que yo elegí): Mantener dos sistemas visuales inevitablemente compromete ambos. Un diseño que funciona al 65% de opacidad sobre negro requiere una opacidad diferente sobre blanco (más cercana al 45%) para lograr el mismo peso perceptual. Cada estado de interacción, cada borde, cada sombra necesita recalibración. Elegí diseñar bien un solo sistema en lugar de dos sistemas de manera adecuada.

El fondo negro absoluto (#000000) maximiza el contraste disponible para cada nivel de texto:

/* My actual typography contrast hierarchy */
.hero__title     { color: var(--color-text-primary); }   /* 21:1 */
.hero__subtitle  { color: var(--color-text-secondary); }  /* 13.7:1 */
.nav a           { color: var(--color-text-secondary); }  /* 13.7:1 */
.nav a:hover     { color: var(--color-text-primary); }    /* 21:1 */

La transición del estado hover (secundario → primario) proporciona retroalimentación funcional enteramente a través del cambio de contraste — sin necesidad de cambio de color.


Contraste y legibilidad

Requisitos de contraste WCAG

Nivel Texto normal (< 18pt) Texto grande (≥ 18pt o 14pt negrita)
AA 4,5:1 3:1
AAA 7:1 4,5:1

La relación de contraste mide la diferencia de luminancia relativa entre los colores del primer plano y el fondo. Una relación de 1:1 significa sin contraste (colores idénticos). Una relación de 21:1 significa contraste máximo (negro sobre blanco o blanco sobre negro).9

Más allá de WCAG: APCA

El algoritmo de contraste de WCAG 2 tiene limitaciones conocidas. El algoritmo trata todos los colores por igual independientemente de la polaridad (oscuro-sobre-claro vs. claro-sobre-oscuro), a pesar de que la investigación demuestra que la percepción humana del contraste difiere significativamente entre los dos modos.10

APCA (Accessible Perceptual Contrast Algorithm) aborda estas limitaciones al tener en cuenta: - Sensibilidad a la polaridad: El texto oscuro sobre fondos claros es más legible que el texto claro sobre fondos oscuros con la misma relación de contraste matemático - Frecuencia espacial: Las fuentes delgadas requieren más contraste que las fuentes negritas al mismo tamaño - Adaptación: El ojo se adapta a la luminancia circundante de la página, lo que afecta el contraste percibido

Se espera que APCA forme la base de los requisitos de contraste de WCAG 3.0. Mi sitio se beneficia de la perspectiva sobre polaridad: dado que uso exclusivamente claro-sobre-oscuro, necesito relaciones de contraste más altas que un sitio en modo claro. Mi nivel de texto más bajo (40% de opacidad, relación 8,4:1) supera incluso el mínimo recomendado por APCA para texto del cuerpo en fondos oscuros.


Color semántico sin color

Los sistemas de color en producción típicamente asignan colores a funciones (verde para éxito, rojo para error). Mi sitio evita completamente el color funcional porque no tiene interfaz transaccional — sin formularios, sin mensajes de estado, sin estados de éxito/error. El contenido es estático.

Si necesitara color semántico, lo agregaría quirúrgicamente:

Función Enfoque típico Mi enfoque hipotético
Éxito Verde Texto blanco + ícono de verificación
Error Rojo Texto blanco + ícono X + énfasis de borde
Advertencia Ámbar Texto blanco + ícono de exclamación

Combinar íconos con texto elimina la comunicación exclusivamente por color, que falla para aproximadamente el 8% de los hombres con deficiencia en la visión del color. El enfoque también preserva mi sistema monocromático. El color serviría como acento, no como elemento estructural.11


La jerarquía centrada en tipografía

Sin color para cargar la jerarquía, la tipografía lo lleva todo en mi sitio:

:root {
  --font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text",
                 "SF Pro Display", "Helvetica Neue", Arial, sans-serif;
  --font-size-display: 5rem;     /* 80px — hero headlines */
  --font-size-7xl:     3.875rem; /* 62px */
  --font-size-base:    1rem;     /* 16px — body text */
  --font-size-xs:      0.75rem;  /* 12px — metadata */
}

Fuentes del sistema, no fuentes web personalizadas. La elección es tanto una decisión brutalista (usar el material nativo de la plataforma) como una decisión de rendimiento (cero latencia en la carga de fuentes, contribuyendo a puntuaciones perfectas de 100/100 en Lighthouse). El tamaño de display (80px) con interletraje ajustado (-0.03em) otorga gravedad a los títulos sin decoración. El texto del cuerpo a 16px con interlineado generoso (1.7) prioriza la legibilidad sobre la densidad.12

La escala tipográfica de 13 pasos desde 0,75rem hasta 5rem proporciona suficiente granularidad para expresar jerarquía solo a través del tamaño. Combinada con los cuatro niveles de opacidad, dispongo de 52 combinaciones potenciales (13 tamaños × 4 opacidades) — más que suficiente para expresar cualquier jerarquía de contenido sin recurrir al color.


Conclusiones clave

Para diseñadores: - Defina paletas de colores en OKLCH en lugar de sRGB; los espacios de color perceptualmente uniformes producen jerarquías predecibles y relaciones de contraste consistentes en toda la paleta - Pruebe su nivel de texto terciario contra WCAG AAA (7:1), no solo AA (4,5:1); el umbral AAA proporciona suficiente margen para condiciones reales de pantalla (bajo brillo, reflejos, pantallas envejecidas) - Considere si su proyecto realmente necesita color; mi sitio demuestra que la tipografía y la opacidad por sí solas pueden sostener una jerarquía visual completa

Para desarrolladores: - Use CSS oklch() para definiciones de color y pruebe las relaciones de contraste tanto con WCAG 2 (estándar actual) como con APCA (estándar próximo); la compatibilidad del navegador con oklch() está disponible en todos los navegadores modernos - Implemente el modo oscuro ajustando la luminosidad y la saturación en el espacio OKLCH en lugar de invertir valores hexadecimales; el ajuste perceptual produce mejores resultados que la inversión matemática - La aplicación estricta de tokens de diseño previene fallas silenciosas de CSS; si un token no existe, el diseño debería cambiar, no el sistema de tokens


Referencias


  1. WebAIM, “The WebAIM Million: 2023 Accessibility Analysis,” 2023. 

  2. Propiedades personalizadas CSS del autor, de critical.css. 10 tokens de color, todos derivados de relaciones de opacidad blanco-sobre-negro. 

  3. Cálculos de contraste WCAG del autor. Primario (21:1), secundario (13,7:1), terciario (8,4:1), todos superando el mínimo AAA de 7:1. 

  4. Experiencia de depuración del autor. --spacing-2xs fue utilizado pero nunca definido en :root. Documentado en las entradas de error de MEMORY.md. 

  5. Hunt, R.W.G., The Reproduction of Colour, Wiley, 2004. 

  6. Poynton, Charles, Digital Video and HD, Morgan Kaufmann, 2012. Corrección gamma y linealidad perceptual. 

  7. Ottosson, Bjorn, “A perceptual color space for image processing,” 2020. Especificación OKLCH. 

  8. Decisión de diseño del autor. Un solo modo oscuro evita el compromiso visual inherente a mantener sistemas paralelos claro/oscuro. 

  9. W3C, “Web Content Accessibility Guidelines (WCAG) 2.1,” 2018. 

  10. Somers, Andrew, “APCA Contrast Calculator,” 2023. 

  11. W3C, “WCAG 2.1 Success Criterion 1.4.1: Use of Color,” 2018. 

  12. Sistema tipográfico del autor. Escala de 13 pasos desde 0,75rem (12px) hasta 5rem (80px). La pila de fuentes del sistema elimina FOIT/FOUT.