Un revisor encontró tres criterios WCAG equivocados en mi plugin de accesibilidad. Fui a mirar y encontré ocho.

Desarrollo un escáner de accesibilidad para WordPress. La semana pasada el revisor de un marketplace me lo rechazó, y entre los motivos estaba este:

Las reglas de conformidad necesitan corrección. «Idioma de las partes» solo valida los atributos lang ya presentes y no puede detectar pasajes en lengua extranjera sin marcar; la regla del landmark principal es WCAG 1.3.6 de nivel AAA pero se comercializa como una comprobación AA; y los id duplicados no deberían presentarse como un incumplimiento de WCAG 2.2 bajo el 4.1.1.

Tres hallazgos. Los tres correctos. Lo que sigue es lo que ocurrió cuando dejé de corregir los tres y comprobé los otros veintidós.

La regla que ya no existe

Empiezo por el tercero, porque es el más fácil de verificar y el más extendidamente equivocado.

El criterio de conformidad 4.1.1 Parsing fue eliminado de las WCAG 2.2. No está obsoleto ni suavizado: eliminado. La Recomendación del W3C lo recoge en la sección de conformidad como «Parsing (Obsolete and removed)». Desapareció porque aquello de lo que protegía — tecnologías de apoyo que se atragantaban con marcado malformado — dejó de ser un modo de fallo real desde que los navegadores y las API de accesibilidad convergieron en cómo recuperarse de HTML defectuoso.

Mi escáner informaba de los atributos id duplicados como incumplimiento de WCAG 4.1.1. Frente a las WCAG 2.2, ese criterio ya no está ahí para incumplirse.

Los id duplicados siguen mereciendo corrección. Rompen las asociaciones label for y las referencias aria-labelledby, de modo que se anuncia el elemento equivocado, o ninguno. Pero eso es un problema del 4.1.2 cuando realmente rompe un nombre accesible, y detectarlo es una comprobación distinta de contar id duplicados. Lo que yo tenía era una comprobación genérica de id duplicados llevando puesto el número de un criterio retirado.

Después comprobé el resto

El revisor había encontrado tres. Podría haber corregido tres. En lugar de eso cogí las 25 reglas y verifiqué cada una contra la Recomendación WCAG 2.2 y contra cómo axe-core clasifica la regla equivalente — porque axe-core es la implementación de referencia sobre la que está construida buena parte de este sector, y hace una distinción que yo había perdido.

Ocho reglas estaban mal.

Regla Declaraba En realidad
Id duplicados 4.1.1 Eliminado de las WCAG 2.2
Un solo landmark main 1.3.6 AAA 1.3.6 es Identify Purpose, un criterio sin relación
Idioma de las partes 3.1.2 AA 3.1.2 es nivel A — y la comprobación no hacía lo que su título prometía
Texto de enlace vago 2.4.4 El 2.4.4 se satisface por el contexto
Niveles de encabezado omitidos 1.3.1 Las WCAG no exigen niveles secuenciales
h1 ausente 1.3.1 Buena práctica
Encabezado vacío 1.3.1 Buena práctica
tabindex positivo 2.4.3 Buena práctica

Algunas merecen una frase.

Texto de enlace vago. El 2.4.4 es Link Purpose (In Context). En contexto. Un enlace que dice «leer más» lo satisface si el párrafo, el elemento de lista o la celda que lo rodea dejan claro el destino — cosa que suele ocurrir. El criterio que exige que el texto del enlace se sostenga solo es el 2.4.9, y es AAA. Así que «leer más» repetido a lo largo de una página es un problema real de usabilidad para quien recorre los enlaces con el tabulador, y no es un incumplimiento de nivel A.

Niveles de encabezado. No existe ningún criterio que exija que un h2 siga a un h1. El 1.3.1 Info and Relationships exige que la estructura transmitida visualmente esté disponible de forma programática — usar encabezados en absoluto es la manera de satisfacerlo. Saltar de h1 a h3 es desordenado y empeora la navegación con lector de pantalla, pero no es lo que dice el 1.3.1. axe-core clasifica heading-order como buena práctica, y lleva años haciéndolo.

Idioma de las partes. Esta estaba mal dos veces. El 3.1.2 es nivel A, no AA — tenía el nivel equivocado. Y la comprobación se titulaba «Los pasajes en lengua extranjera deben declarar su idioma», lo que prometía algo que ninguna comprobación automática puede hacer: saber que un pasaje está en otro idioma cuando nada lo señala. Lo que el código hacía en realidad era validar los atributos lang ya presentes. Es una comprobación útil. No es la comprobación que anunciaba el título.

Cuáles son entonces las cifras reales

25 comprobaciones. Dieciocho se corresponden con un criterio de conformidad WCAG 2.2, repartidas en catorce criterios distintos de nivel A y AA: 1.1.1, 1.3.1, 1.3.5, 1.4.2, 1.4.3, 1.4.4, 2.4.1, 2.4.2, 2.4.4, 2.5.8, 3.1.1, 3.1.2, 3.3.2 y 4.1.2.

Siete son buenas prácticas. Merecen corregirse, no son incumplimientos.

Antes de la revisión, la página de producto decía «25 comprobaciones automáticas en los niveles A y AA de WCAG 2.2» y listaba el 4.1.1 entre los criterios cubiertos. Ambas cosas eran falsas, y la segunda era comprobablemente falsa por cualquiera que hubiera leído la Recomendación 2.2.

Por qué esto no es pedantería

Aquí viene la parte que me hizo dejar de tratarlo como un problema de etiquetas.

El plugin incluye un generador para la información de accesibilidad que exige la European Accessibility Act. Rellena la sección de «barreras conocidas» a partir del escaneo más reciente y — este era el argumento de venta — asocia a cada barrera su criterio de conformidad WCAG.

Así que ocho reglas que citaban criterios equivocados, obsoletos o ajenos estaban escribiendo esos números dentro de un documento que el propietario del sitio publica como declaración legal sobre su propio servicio.

Una declaración de conformidad no es un informe. Un informe que exagera te estropea la tarde. Una declaración publicada que cita un criterio que no existe, en un documento que estás legalmente obligado a mantener, es otra categoría de error — y de las que descubre tu cliente, no tú.

Ese es el argumento a favor de la distinción, y es el único que importa. Una herramienta que presenta cada hallazgo como incumplimiento WCAG infla dos cifras: la suya — 25 comprobaciones WCAG se lee mejor que 18 — y la tuya. Y tu cifra inflada es la que acaba siendo pública.

Qué he cambiado

Cada regla declara ahora lo que es:

{
    id: 'heading_order',
    wcag: '',
    level: '',
    standard: 'best-practice',
    ...
}

El informe imprime el criterio donde lo hay, y Buena práctica donde no lo hay, en lugar de un WCAG () vacío.

El generador exige ahora dos condiciones independientes antes de escribir un criterio dentro de un documento legal: la regla debe estar marcada como asociada a WCAG, y su valor debe coincidir con ^\d+\.\d+\.\d+$. Cualquiera de las dos por separado habría bastado para impedir lo que pasó. Quería la que sobrevive a que alguien edite la otra.

Y los textos comerciales dicen ahora 18 y 7, en el readme, en la documentación y en la ficha del marketplace. Fue el commit menos agradable de la semana y el que volvería a hacer.

Si construyes o compras una de estas herramientas

Tres preguntas que merece la pena hacerse, y ninguna exige fiarse de mí.

¿Sigue informando del 4.1.1? Treinta segundos para comprobarlo, y te dice cuándo se leyó por última vez el conjunto de reglas contra el estándar en lugar de copiarlo de otra herramienta.

¿Distingue los criterios de conformidad de las buenas prácticas? Si cada hallazgo lleva un número de criterio, al menos algunos de esos números son decoración. La implementación de referencia sobre la que funciona este sector marca alrededor de una cuarta parte de sus reglas como buena práctica. Una herramienta que no tiene ninguna no es más estricta: es menos cuidadosa.

¿A dónde va el criterio después del informe? Si fluye hacia una declaración, un sello, un PDF o cualquier cosa que un cliente publique, su exactitud deja de ser una cuestión de calidad interna.

Lo que no ha cambiado

Las pruebas automáticas encuentran alrededor de un tercio de las barreras reales de accesibilidad. Corregir las etiquetas no mueve esa cifra. Un informe limpio es una buena señal, no una declaración de conformidad, y las pruebas con teclado y lector de pantalla hechas por una persona siguen siendo la única forma de saberlo.

Lo que la revisión cambió es más estrecho y, creo, valía la semana: cuando ahora mi herramienta dice WCAG, lo dice en serio.