
El tema de la desactivación de enlaces apareció en mi trabajo el otro día. De alguna manera, el año pasado se agregó un estilo de ancla “discapacitado” a nuestros estilos de tipografía cuando no estaba mirando. Sin embargo, hay un problema: no hay una forma real de deshabilitar un <a>
enlace (con un href
atributo) en HTML. Sin mencionar, ¿por qué querrías hacerlo? Los enlaces son la base de la web.
En cierto momento, parecía que mis compañeros de trabajo no iban a aceptar este hecho, así que comencé a pensar en cómo se podría lograr. Sabiendo que se necesitaría mucho, quería demostrar que no valía la pena el esfuerzo y el código para respaldar una interacción tan poco convencional, pero temía que, al mostrar que se podía hacer, ignorarían todas mis advertencias y solo usarían mi ejemplo como prueba de que estaba bien. Esto aún no me ha afectado del todo, pero pensé que podríamos seguir con mi investigación.
Lo primero es lo primero:
Simplemente no lo hagas.
Un enlace desactivado no es un enlace, es solo texto. Necesita repensar su diseño si requiere deshabilitar un enlace.
Bootstrap tiene ejemplos de aplicación de .disabled
class para anclar etiquetas, y las odio por ello. Al menos mencionan que la clase solo proporciona un estilo para discapacitados, pero esto es engañoso. Debe hacer algo más que hacer que un enlace parezca deshabilitado si realmente desea deshabilitarlo.
Manera segura: eliminar el href
Si ha decidido que va a ignorar mi advertencia y continuar con la desactivación de un enlace, entonces la eliminación de la href
atributo es la mejor manera que conozco.
Directamente de la especificación oficial de hipervínculo:
El href
atributo en a
y area
no se requieren elementos; cuando esos elementos no tienen href
atributos que no crean hipervínculos.
Una definición más fácil de entender de MDN:
Este atributo se puede omitir (a partir de HTML5) para crear un enlace de marcador de posición. Un vínculo de marcador de posición se parece a un hipervínculo tradicional, pero no conduce a ninguna parte.
Aquí está el código JavaScript básico para configurar y eliminar el href
atributo:
/*
* Use your preferred method of targeting a link
*
* document.getElementById('MyLink');
* document.querySelector('.link-class');
* document.querySelector('[href="https://unfetteredthoughts.net"]');
*/
// "Disable" link by removing the href property
link.href="";
// Enable link by setting the href property
link.href="https://unfetteredthoughts.net";
Diseñar esto a través de CSS también es bastante sencillo:
a {
/* Disabled link styles */
}
a:link, a:visited { /* or a[href] */
/* Enabled link styles */
}
¡Eso es todo lo que necesitas hacer!
Eso no es suficiente, quiero algo más complejo para poder lucir más inteligente.
Si simplemente tiene que diseñar en exceso alguna solución extrema, aquí hay algunas cosas a considerar. Con suerte, prestará atención y reconocerá que lo que estoy a punto de mostrarles no vale la pena el esfuerzo.
Primero, necesitamos diseñar nuestro enlace para que parezca deshabilitado.
.isDisabled {
color: currentColor;
cursor: not-allowed;
opacity: 0.5;
text-decoration: none;
}
<a class="isDisabled" href="https://unfetteredthoughts.net">Disabled Link</a>
Ajuste color
a currentColor
debe restablecer el color de la fuente a su color normal de texto sin vínculo. También estoy colocando el cursor del mouse en not-allowed
para mostrar un buen indicador al pasar el mouse de que la acción normal no está permitida. Ya hemos dejado de lado a los usuarios que no utilizan el mouse y que no pueden desplazarse, principalmente el tacto y el teclado, por lo que no obtendrán esta indicación. A continuación, la opacidad se reduce a la mitad. Según WCAG, los elementos deshabilitados no necesitan cumplir con las pautas de contraste de color. Creo que esto es muy arriesgado ya que es básicamente texto sin formato en este punto, y reducir la opacidad a la mitad haría muy difícil de leer para los usuarios con baja visión, otra razón por la que odio esto. Por último, se elimina el subrayado de la decoración del texto, ya que suele ser el mejor indicador de que algo es un enlace. ¡Esto parece un enlace deshabilitado!
¡Pero no está realmente discapacitado! Un usuario aún puede hacer clic / tocar en este enlace. Te escucho gritar sobre pointer-events
.
.isDisabled {
...
pointer-events: none;
}
Ok, hemos terminado! ¡Enlace desactivado logrado! Excepto, solo está realmente deshabilitado para los usuarios del mouse que hacen clic y tocan a los usuarios que tocan. ¿Qué pasa con los navegadores que no admiten pointer-events
? Según caniuse, esto no es compatible con Opera Mini e IEpointer-events a menos que display
se establece en block
o inline-block
. Además, la configuración pointer-events
a none
sobrescribe nuestro bonito not-allowed
cursor, por lo que ahora los usuarios del mouse no obtendrán esa indicación visual adicional de que el enlace está deshabilitado. Esto ya está empezando a desmoronarse. Ahora tenemos que cambiar nuestro marcado y CSS …
.isDisabled {
cursor: not-allowed;
opacity: 0.5;
}
.isDisabled > a {
color: currentColor;
display: inline-block; /* For IE11/ MS Edge bug */
pointer-events: none;
text-decoration: none;
}
<span class="isDisabled"><a href="https://unfetteredthoughts.net">Disabled Link</a></span>
Envolviendo el enlace en un <
span
>
y agregando el isDisabled
clase nos da la mitad de nuestro estilo visual discapacitado. Un buen efecto secundario aquí es que la clase deshabilitada ahora es genérica y se puede usar en otros elementos, como botones y elementos de formulario. La etiqueta de ancla real ahora tiene el pointer-events
y text-decoration
ajustado a none
.
¿Qué pasa con los usuarios de teclado? Los usuarios de teclado utilizarán el ENTER
clave para activar enlaces. pointer-events
son solo para punteros, no hay eventos de teclado. También debemos evitar la activación de navegadores antiguos que no son compatibles pointer-events
. Ahora tenemos que introducir algo de JavaScript.
Trae el JavaScript
// After using preferred method to target link
link.addEventListener('click', function (event) {
if (this.parentElement.classList.contains('isDisabled')) {
event.preventDefault();
}
});
Ahora nuestro enlace parece deshabilitado y no responde a la activación mediante clics, toques y el ENTER
llave. ¡Pero todavía no hemos terminado! Los usuarios de lectores de pantalla no tienen forma de saber que este enlace está desactivado. Necesitamos describir este enlace como desactivado. El disabled
El atributo no es válido en los enlaces, pero podemos usar aria-disabled="true"
.
<span class="isDisabled"><a href="https://unfetteredthoughts.net" aria-disabled="true">Disabled Link</a></span>
Ahora voy a aprovechar esta oportunidad para diseñar el enlace en función de la aria-disabled
atributo. Me gusta usar atributos ARIA como ganchos para CSS porque tener elementos con un estilo incorrecto es un indicador de que falta una accesibilidad importante.
.isDisabled {
cursor: not-allowed;
opacity: 0.5;
}
a[aria-disabled="true"] {
color: currentColor;
display: inline-block; /* For IE11/ MS Edge bug */
pointer-events: none;
text-decoration: none;
}
Ahora nuestros enlaces se ven deshabilitados, actúan deshabilitados y se describen como deshabilitados.
Desafortunadamente, aunque el enlace se describe como deshabilitado, algunos lectores de pantalla (JAWS) aún anunciarán que se puede hacer clic. Lo hace para cualquier elemento que tenga un detector de clics. Esto se debe a la tendencia del desarrollador a crear elementos no interactivos como div
y span
como elementos pseudo-interactivos con un simple oyente. No podemos hacer nada al respecto aquí. Todo lo que hemos hecho para eliminar cualquier indicio de que se trata de un vínculo ha sido frustrado por la tecnología de asistencia que estábamos tratando de engañar, irónicamente porque hemos intentado engañarlo antes.
Pero, ¿y si trasladamos al oyente al cuerpo?
document.body.addEventListener('click', function (event) {
// filter out clicks on any other elements
if (event.target.nodeName == 'A' && event.target.getAttribute('aria-disabled') == 'true') {
event.preventDefault();
}
});
¿Terminamos? Bueno en realidad no. En algún momento, necesitaremos habilitar estos enlaces, por lo que debemos agregar código adicional que alternará este estado / comportamiento.
function disableLink(link) {
// 1. Add isDisabled class to parent span
link.parentElement.classList.add('isDisabled');
// 2. Store href so we can add it later
link.setAttribute('data-href', link.href);
// 3. Remove href
link.href="";
// 4. Set aria-disabled to 'true'
link.setAttribute('aria-disabled', 'true');
}
function enableLink(link) {
// 1. Remove 'isDisabled' class from parent span
link.parentElement.classList.remove('isDisabled');
// 2. Set href
link.href = link.getAttribute('data-href');
// 3. Remove 'aria-disabled', better than setting to false
link.removeAttribute('aria-disabled');
}
Eso es. Ahora tenemos un enlace deshabilitado que está deshabilitado visual, funcional y semánticamente para todos los usuarios. Solo tomó 10 líneas de CSS, 15 líneas de JavaScript (incluido 1 oyente en el cuerpo) y 2 elementos HTML.
En serio amigos, simplemente no lo hagas.