Lo que encontró una auditoría de accesibilidad en mis propias insignias de SwiftUI
Hice una auditoría de accesibilidad enfocada, antes del lanzamiento v1 de Deep Cut Atlas: contraste, etiquetas de VoiceOver, Dynamic Type. Dos de los hallazgos resultaron ser el mismo error disfrazado distinto, y arreglarlos me enseñó algo sobre cómo las insignias con fondo translúcido fallan las pruebas de contraste en silencio, sin importar qué color elijas.
El error: texto del mismo tono sobre su propio fondo tintado
La app tiene insignias pequeñas en forma de “pastilla” de colores. Una muestra el tipo de grabación (Álbum/EP/Sencillo/Compilación) en un chip codificado por color, otra marca un lanzamiento editorial de Apple como “Destacado” en dorado. Ambas usaban el mismo patrón: texto de un tono, sobre un fondo del mismo tono a 18% de opacidad.
Se ve bien. Se lee como “acorde a la marca.” Y mide como ilegible. De hecho calculé a mano las razones de contraste WCAG (luminancia relativa, la fórmula real, no un estimado): la insignia naranja dio 1.73:1, la azul 2.87:1, y la insignia amarilla “Destacado”, la peor de toda la app, 1.27:1. WCAG AA pide 4.5:1 para este tamaño de texto. Ninguna se acercaba.
La idea que hizo clic: mezclar un color con alfa sobre un fondo neutro claro empuja tanto el texto como el fondo hacia el mismo punto en el espacio de luminancia. No importa qué tono elijas, el mismo color sobre su propio tinte es estructuralmente de bajo contraste. Cambiar naranja por azul no lo arregla, solo fallas de otra forma.
La solución
Desacoplar el color del texto del tinte. Las insignias ahora usan .primary (que iOS garantiza que contrasta bien contra los fondos del sistema tanto en modo claro como oscuro) para el texto real, y un pequeño punto de color, o para la insignia Destacado, el ícono de estrella que ya existía, lleva la codificación por color en su lugar. El escaneo visual rápido por color sigue ahí, solo que ya no hace falta entrecerrar los ojos para leer la etiqueta.
Un arreglo más pequeño y relacionado: el estado seleccionado de un chip de filtro usaba texto blanco sobre el relleno del color de acento de la app, 4.02:1 en modo claro, 3.65:1 en oscuro, ambos apenas por debajo del mínimo de 4.5:1. WCAG tiene una excepción: el texto en negrita a este tamaño solo necesita 3:1. Así que en vez de tocar colores, simplemente puse la etiqueta seleccionada en negrita. Pase libre, una palabra en el código.
Lección: “a mí se me ve bien” no es una prueba de contraste. Calcular la razón de verdad (o correr un verificador de contraste automatizado) convierte un vago “¿esto se puede leer?” en un sí o no accionable, y una vez que ves el patrón de mismo-tono-sobre-su-propio-tinte una vez, empiezas a notarlo en todas partes.
Lecturas relacionadas
Una corrección de accesibilidad de dos líneas que necesitó un teléfono real para comprobarse
VoiceOver no podía distinguir cuál playlist estaba vinculada. La corrección fue .accessibilityAddTraits(.isSelected). Comprobarlo implicó un desbloqueo, un rebuild, y una herramienta de espejado que no encontraba su ventana.
Verificar una solución en un ajuste extremo reveló un segundo bug
Los títulos largos se truncaban exactamente como estaba diseñado. La insignia de una sola palabra, el campo 'demasiado corto para necesitar un límite de línea alguna vez', se dividió con guion en 'Al-bum' apilado dentro de una cápsula.
Solo arreglé la captura que me pidieron, no las otras que también estaban rotas
Una captura de marketing recapturada parecía terminada, hasta la pregunta desinflante: ¿de verdad esta es toda captura que se había pedido? Las otras tres del mismo conjunto también estaban desactualizadas, cada una a su manera.