Addaw, ir a inicio Donar

Fallo común WCAG 2.2

F42Enlaces falsos hechos con span, div o img y JavaScript

Nombre oficial en el W3C: Fallo de los criterios de conformidad 1.3.1, 2.1.1, 2.1.3 o 4.1.2 al emular enlaces

En pocas palabras

El error es crear un «enlace» con un elemento que no lo es, como un span, un div o una imagen, y hacer que lleve a otra página con JavaScript. Funciona con el ratón, pero el teclado no llega a él y el lector de pantalla no lo anuncia como enlace. Lo correcto es usar el elemento a con su atributo href.

Por qué es importante

Un enlace de verdad trae de serie todo lo necesario. El navegador lo incluye en el recorrido con el tabulador, lo activa con Intro y lo anuncia como «enlace».

  • Quien usa solo el teclado no puede llegar a un enlace falso ni activarlo.
  • Quien usa un lector de pantalla (programa que lee en voz alta lo que hay en la pantalla) lo oye como texto normal. Tampoco aparece en la lista de enlaces que el lector ofrece para moverse rápido.
  • Añadir soporte de teclado no basta. Un div que responde a Intro sigue sin anunciarse como enlace.

Cómo evitarlo

  1. Para llevar a otra página, o a otra parte de la misma, use siempre <a href="…">.
  2. No ponga onclick en un span, un div, una img o una fila de tabla para navegar.
  3. Si el enlace es una imagen, meta la imagen dentro del <a> y dele un alt que diga adónde lleva.
  4. En tarjetas de producto o de noticia, ponga un enlace real en el título de la tarjeta.
  5. Evite role="link" con tabindex="0" sobre un div. Es posible, pero obliga a programarlo todo a mano y es fácil olvidar algo. El elemento nativo siempre es mejor.

Ejemplo práctico

Es habitual en fichas de producto, tarjetas de noticias y migas de pan. Un texto con aspecto de enlace es en realidad un span o un div. Un manejador onclick hace que cambie de página.

Así no: Enlace simulado con un span y onclick

El texto parece un enlace y funciona con el ratón. Pero no recibe el foco con Tab ni se activa con Intro. El lector de pantalla lo lee como texto normal: no dice «enlace» ni lo muestra en la lista de enlaces. Para notarlo, recorra la demo con Tab o con la lista de enlaces del lector (NVDA+F7).

Captura de pantalla del ejemplo incorrecto: Enlace simulado con un span y onclick
Así se ve el ejemplo incorrecto.

La demostración contiene, a propósito, el error de accesibilidad que se explica.

Ver el código del ejemplo incorrecto
<style>
  .enlace { color: #744E9A; text-decoration: underline; cursor: pointer; }
  section { margin-top: 16px; padding: 8px; }
  section:target { background: #f3eef8; }
</style>
<h2>Zapatillas de montaña Trail 300</h2>
<p>59,90 € · <span class="enlace" onclick="location.hash = 'envios'">Consultar plazos de envío</span></p>
<section id="envios">
  <h3>Plazos de envío</h3>
  <p>Península: 24-48 horas. Baleares y Canarias: 3-5 días laborables.</p>
</section>

Así sí: Enlace nativo con a y href

Se cambia el span por un elemento a con href. El navegador ya lo trata como enlace, sin script. Lo incluye en el orden de tabulación, lo activa con Intro y lo muestra en la lista de enlaces del lector de pantalla.

Pruébelo aquí:

Ver el código del ejemplo correcto
<style>
  .enlace { color: #744E9A; text-decoration: underline; }
  section { margin-top: 16px; padding: 8px; }
  section:target { background: #f3eef8; }
</style>
<h2>Zapatillas de montaña Trail 300</h2>
<p>59,90 € · <a class="enlace" href="#envios">Consultar plazos de envío</a></p>
<section id="envios">
  <h3>Plazos de envío</h3>
  <p>Península: 24-48 horas. Baleares y Canarias: 3-5 días laborables.</p>
</section>

Cómo comprobarlo

Teclado

  1. Recorrer la página con Tab y Mayús+Tab.
  2. Comprobar que cada texto con aspecto de enlace recibe el foco y muestra un indicador visible.
  3. Pulsar Intro sobre cada uno. Debe llevar al mismo sitio que el clic del ratón.

Lector de pantalla (NVDA o VoiceOver)

  1. Abrir la lista de enlaces: NVDA+F7 en NVDA, o el rotor con VO+U en VoiceOver.
  2. Comprobar que aparecen todos los enlaces visibles de la página.
  3. Situarse sobre el enlace y escuchar la función que se anuncia.

Debería anunciar: «Enlace, Consultar plazos de envío»

Herramientas del navegador

  1. Abrir las herramientas de desarrollo (F12) e inspeccionar el texto con aspecto de enlace.
  2. En la pestaña Accesibilidad, comprobar que la función (role) es «link». No debe ser «generic» ni texto estático.
  3. En la pestaña Elementos, revisar los detectores de eventos (Event Listeners). Así se encuentran elementos no interactivos con manejadores de clic.

Validación automática

  1. axe DevTools, WAVE y Lighthouse no suelen detectar un span o div con onclick. No pueden saber si el script navega o no, así que la revisión es manual.
  2. Sí detectan casos parecidos, como un div role="link" sin nombre accesible. Pero no avisan si le falta el soporte de teclado.

Errores frecuentes en auditorías

  • Tarjetas de producto o de noticia con onclick en el div que las contiene y sin ningún enlace real dentro.
  • Usar <a onclick="..."> sin atributo href. Sin él, el elemento no es un enlace: no recibe el foco con Tab y se lee como texto.
  • Filas de tabla (tr) que abren el detalle de un registro solo con clic. Es habitual en listados de intranets y ERP.
  • Añadir role="link" y tabindex="0" a un div, pero olvidar que se active con la tecla Intro.
Ver el texto completo del W3C (traducción al español)

Esta es una traducción no oficial al español de la técnica F42 de Techniques for WCAG 2.2, del W3C. Puede contener errores. El único documento oficial y normativo es la versión original en inglés, publicada en el sitio web del W3C.

Aplicabilidad

HTML

Descripción

Este fallo se produce cuando se asocian manejadores de eventos JavaScript a elementos para emular enlaces. Un enlace creado de esta manera no puede alcanzarse con el tabulador desde el teclado y no recibe el foco del teclado como el resto de controles o enlaces. Si se usan eventos de script para emular enlaces, los agentes de usuario, incluida la tecnología de asistencia, pueden no ser capaces de identificar los enlaces del contenido como enlaces. Pueden reconocerse como controles interactivos, pero aun así no reconocerse como enlaces. Estos elementos no aparecen en la lista de enlaces que generan los agentes de usuario o la tecnología de asistencia.

Es posible usar el atributo role de ARIA para identificar un elemento anónimo como control de enlace ante las tecnologías de asistencia. Sin embargo, la práctica recomendada para ARIA aconseja usar elementos nativos siempre que sea posible, por lo que no se recomienda usar el atributo role para identificar elementos anónimos como enlaces.

Los elementos a y area están pensados para marcar enlaces.

Ejemplos

Añadir un script a un elemento span

Se añade un manejador de eventos mediante script a un elemento span para que funcione como un enlace al hacer clic con el ratón. La tecnología de asistencia no reconoce este elemento como un enlace.

<span onclick="location.href='newpage.html'">Fake link</span>

Añadir un script a un elemento img

Se añade un manejador de eventos mediante script a un elemento img para que funcione como un enlace al hacer clic con el ratón. La tecnología de asistencia no reconoce este elemento como un enlace.

<img src="go.gif" alt="go to the new page" onclick="location.href='newpage.html'">

Añadir un script a un elemento img, con compatibilidad con el teclado

Se añade un manejador de eventos mediante script a un elemento img para que funcione como un enlace. En este ejemplo, la función de enlace puede activarse con el ratón o con la tecla Intro si el agente de usuario incluye el elemento en la cadena de tabulación. No obstante, el elemento no se reconocerá como un enlace.

function doNav(url){
  window.location.href = url;
}
function doKeyPress(url){
  //if the enter key was pressed
  if (window.event.type == "keypress" && window.event.keyCode == 13){
    doNav(url);
  }
}

El marcado de la imagen es:

<p>
  <img src="bargain.jpg"
  tabindex="0" 
  alt="View Bargains"
  onclick="doNav('viewbargains.html');"
  onkeypress="doKeyPress('viewbargains.html');">
</p>

Añadir un script a un elemento div

Este ejemplo usa un script para hacer que un elemento div se comporte como un enlace. Aunque el autor ha proporcionado acceso completo por teclado y ha separado los manejadores de eventos del marcado para permitir reutilizar el contenido, la tecnología de asistencia no reconocerá el elemento div como un enlace.

window.onload = init;
function init(){
  var objAnchor = document.getElementById('linklike');
  objAnchor.onclick = function(event){return changeLocation(event,
   'surveyresults.html');};
      objAnchor.onkeypress = function(event){return changeLocation(event,
   'surveyresults.html');};
}
function changeLocation(objEvent, strLocation){
  var iKeyCode;
  if (objEvent && objEvent.type == 'keypress'){
    if (objEvent.keyCode){
      iKeyCode = objEvent.keyCode;
    }
    else if (objEvent.which){
      iKeyCode = objEvent.which;
    }
  if (iKeyCode != 13 && iKeyCode != 32){
    return true;
    }
  }
  window.location.href = strLocation;
}

El marcado del elemento div es:

<div id="linklike">View the results of the survey.</div>

Pruebas

Procedimiento

Para todos los elementos presentados como enlaces que usen manejadores de eventos JavaScript para que el elemento emule un enlace:

  1. Comprobar si la función (role) del elemento determinada por software es "link".
  2. Comprobar si el enlace emulado puede activarse con el teclado.

Resultados esperados

  • Si la comprobación n.º 1 es falsa, se da esta condición de fallo y el contenido falla los criterios de conformidad 1.3.1 Información y relaciones y 4.1.2 Nombre, función y valor. Si la comprobación n.º 2 es falsa, se da esta condición de fallo y el contenido falla los criterios de conformidad 2.1.1 Teclado y 2.1.3 Teclado (sin excepciones).

Recursos

Cómo lo comprobamos en ADDAW

Este error es uno de los que buscamos en cada auditoría de ADDAW. Se lo entregamos con capturas y la forma de corregirlo.

Solicitar una auditoría

Basado en la técnica F42 del W3C (WCAG 2.2). Explicación y ejemplos: ADDAW. Traducción no oficial del texto del W3C © W3C, licencia de documentos del W3C. ¿Ha visto un error? Escríbanos.