Al montar esta web tuve que elegir un gris para el texto secundario. La respuesta fácil era coger zinc-500 de Tailwind, que es lo que usa medio internet. Lo medí antes de usarlo y no llega. Te cuento los números, porque son más útiles que la conclusión.
El mínimo no es una opinión
Las pautas de accesibilidad WCAG en nivel AA piden 4,5:1 de contraste para texto normal y 3:1 para texto grande —a partir de 24 px, o 18,5 px en negrita—. En España esto no es una recomendación de diseño: el Real Decreto 1112/2018 obliga al sector público, y la Ley 11/2023 lo extiende a bastantes empresas privadas. Aunque no te obligue, un texto que no se lee no vende nada.
El contraste se calcula sobre la luminancia relativa de los dos colores, no sobre lo que parece a ojo. Y ahí está la trampa: sobre negro puro, un gris que parece legible en tu monitor bueno se cae en cuanto alguien lo abre en la calle con el móvil al sol.
Los números, medidos sobre #000000
| Gris | Contraste | ¿Vale para texto normal? |
|---|---|---|
#FFFFFF | 21,00:1 | Sí |
#A3A3A3 | 8,33:1 | Sí, con margen |
#8A8A8A | 6,08:1 | Sí |
#757575 | 4,56:1 | Sí, por los pelos |
#71717A (zinc-500) | 4,35:1 | No |
#5A5A5A | 3,04:1 | Solo texto grande |
#3D3D3D | 1,93:1 | Solo decoración |
zinc-500 se queda a 0,15 puntos. No es un fallo escandaloso, pero es un fallo: si alguien pasa una auditoría automática, sale marcado. Y lo curioso es que zinc-400 (#A1A1AA) da 8,19:1 y va sobradísimo — el escalón entre los dos es enorme, así que no hay que sufrir por perder elegancia. Se sube un peldaño y ya está.
Qué hicimos aquí
Definimos tres tokens de texto y ninguno más:
#FFFFFFpara titulares y texto principal.#A3A3A3para texto secundario y descripciones. 8,33:1 deja margen de sobra.#858585para pies y notas menores. Es el suelo: por debajo de ese valor no se escribe texto en esta web, y punto.
Tres tokens obligan a decidir la jerarquía en vez de ir bajando el gris cada vez que algo «pesa demasiado». Es una restricción, y por eso funciona.
La trampa que casi se nos cuela
El suelo iba a ser #757575, que da 4,56:1 y cumple. Cumple sobre negro puro. Pero esta web tiene tarjetas con un fondo apenas más claro que el fondo base —#0a0a0a— y ahí ese mismo gris se queda en 4,30:1. Sobre la superficie de un nivel más, #141414, baja a 4,00:1.
Es decir: el token pasaba la comprobación contra el color que habíamos medido, y fallaba justo en los tres sitios donde se usaba de verdad. Por eso el suelo acabó siendo #858585, que da 5,69:1 sobre negro, 5,37:1 sobre #0a0a0a y 4,99:1 sobre #141414.
Mide cada gris contra todos los fondos sobre los que puede acabar, no solo contra el fondo de la página. Una tarjeta elevada de un 4 % de luminosidad se come 0,3 puntos de ratio sin que se note a ojo.
Lo que esto no arregla
Que el contraste sea correcto no hace accesible una web. Faltan el foco visible del teclado, el orden de tabulación, los textos alternativos, los nombres accesibles de los controles y que el zoom al 200 % no rompa la maquetación. El contraste es de lo poco que se puede medir con una fórmula, y por eso es lo primero que se comprueba y lo primero que se arregla — no lo último que hace falta.
Tampoco hemos hablado del nivel AAA, que pide 7:1. Nuestro secundario lo cumple sin pretenderlo; el suelo, no.
Cómo comprobar el tuyo en un minuto
Abre las herramientas de desarrollo del navegador, inspecciona el texto y mira el selector de color: Chrome y Firefox te enseñan el ratio de contraste con el fondo real y te avisan si no llega a AA. Si prefieres calcularlo tú, la fórmula está en la propia especificación de WCAG, enlazada arriba.
Si al mirarlo te sale un número por debajo de 4,5 en algún texto de tu web, tienes un arreglo de diez minutos y una excusa menos.
Cualquier duda me dices y lo vemos.