Info Valor de href de relleno ("#" o javascript:)
Por qué se desaconsejan los enlaces href="#" y javascript: para controles manejados por JavaScript, y qué usar en su lugar.
El validador marca <a href="#"> y <a href="javascript:..."> — enlaces cuyo destino es un relleno en vez de una URL real.
Ejemplo
<!-- Desaconsejado -->
<a href="#" onclick="abrirMenu()">Menú</a>
<a href="javascript:void(0)" onclick="abrirMenu()">Menú</a>
<!-- Preferido, si no navega a ningún lado -->
<button type="button" onclick="abrirMenu()">Menú</button>Por qué importa
Ambos patrones existen para que un elemento se vea y se comporte como un enlace mientras en realidad está manejado por completo por JavaScript — pero una etiqueta <a> real con cualquiera de los dos valores igual se anuncia como un enlace ante buscadores y lectores de pantalla, prometiendo un destino que no existe. href="#" también tiene un efecto secundario visible si el manejador de clic no llama a preventDefault(): la página salta hasta arriba. Un <button> es el elemento semánticamente correcto para un control que dispara un comportamiento sin navegar — es operable por teclado y amigable con lectores de pantalla por defecto, sin ninguno de los efectos secundarios de un href de relleno.
Frequently asked questions
¿href="#seccion-id" también se marca?
No — un fragmento que nombra un id real es un enlace legítimo dentro de la misma página y esta revisión no lo toca (ver la revisión separada broken-anchor-link para cuando ese id en realidad no existe). Aquí solo se marcan el # de relleno a secas y las URLs javascript:.
¿Por qué no simplemente usar preventDefault() y mantener la etiqueta <a>?
Se puede, y evita el efecto secundario del salto de página, pero el elemento sigue siendo semánticamente un enlace sin ningún destino real — un <button> comunica mejor su comportamiento real a la tecnología de asistencia y no necesita el código defensivo extra.