Cómo deshabilitar enlaces HTML

263

Tengo un botón de enlace dentro de uno <td>que tengo que deshabilitar. Esto funciona en IE pero no funciona en Firefox y Chrome. Estructura es - Enlace dentro de a <td>. No puedo agregar ningún contenedor en el <td>(como div / span)

Intenté todo lo siguiente pero no funcionaba en Firefox (usando 1.4.2 js):

$(td).children().each(function () {
        $(this).attr('disabled', 'disabled');
  });


  $(td).children().attr('disabled', 'disabled');

  $(td).children().attr('disabled', true);

  $(td).children().attr('disabled', 'true');

Nota: No puedo cancelar el registro de la función de clic para la etiqueta de anclaje, ya que se registra dinámicamente. Y DEBO MOSTRAR EL ENLACE EN MODO DESACTIVADO.

Ankit
fuente
Pregunta única de CSS: stackoverflow.com/questions/2091168/disable-a-link-using-css
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Respuestas:

510

No puede deshabilitar un enlace (de forma portátil). Puede usar una de estas técnicas (cada una con sus propios beneficios y desventajas).

Forma CSS

Esta debería ser la forma correcta (pero ver más adelante) de hacerlo cuando la mayoría de los navegadores lo admitirán:

a.disabled {
    pointer-events: none;
}

Es lo que, por ejemplo, Bootstrap 3.x hace. Actualmente (2016) solo es compatible con Chrome, Firefox y Opera (19+). Internet Explorer comenzó a admitir esto desde la versión 11, pero no para enlaces, sin embargo, está disponible en un elemento externo como:

span.disable-links {
    pointer-events: none;
}

Con:

<span class="disable-links"><a href="#">...</a></span>

Solución alterna

Probablemente, necesitemos definir una clase CSS para, pointer-events: nonepero ¿qué pasa si reutilizamos el disabledatributo en lugar de una clase CSS? Estrictamente hablando disabledno es compatible, <a>pero los navegadores no se quejarán por atributos desconocidos . Usar el disabledatributo IE ignorará pointer-eventspero honrará el disabledatributo específico de IE ; otros navegadores compatibles con CSS ignorarán los atributos y el honor desconocidos . Más fácil de escribir que explicar:disabledpointer-events

a[disabled] {
    pointer-events: none;
}

Otra opción para IE 11 es establecer displayelementos de enlace para blocko inline-block:

<a style="pointer-events: none; display: inline-block;" href="#">...</a>

Tenga en cuenta que esta puede ser una solución portátil si necesita admitir IE (y puede cambiar su HTML) pero ...

Dicho todo esto, tenga en cuenta que pointer-eventssolo desactiva ... eventos de puntero. Los enlaces seguirán siendo navegables a través del teclado, entonces también debe aplicar una de las otras técnicas descritas aquí.

Atención

En combinación con la técnica CSS descrita anteriormente, puede usarla tabindexde una manera no estándar para evitar que un elemento se enfoque:

<a href="#" disabled tabindex="-1">...</a>

Nunca verifiqué su compatibilidad con muchos navegadores, entonces es posible que desee probarlo usted mismo antes de usar esto. Tiene la ventaja de trabajar sin JavaScript. Desafortunadamente (pero obviamente) tabindexno se puede cambiar de CSS.

Interceptar clics

Use una función hrefa a JavaScript, verifique la condición (o el atributo deshabilitado en sí) y no haga nada en el caso.

$("td > a").on("click", function(event){
    if ($(this).is("[disabled]")) {
        event.preventDefault();
    }
});

Para deshabilitar los enlaces, haga esto:

$("td > a").attr("disabled", "disabled");

Para volver a habilitarlos:

$("td > a").removeAttr("disabled");

Si lo desea .is("[disabled]"), puede usar .attr("disabled") != undefined(jQuery 1.6+ siempre volverá undefinedcuando el atributo no esté configurado) pero is()es mucho más claro (gracias a Dave Stewart por este consejo). Tenga en cuenta que estoy usando el disabledatributo de una manera no estándar, si le importa esto, reemplace el atributo con una clase y reemplace .is("[disabled]")con .hasClass("disabled")(agregar y eliminar con addClass()y removeClass()).

Zoltán Tamási señaló en un comentario que "en algunos casos, el evento click ya está vinculado a alguna función" real "(por ejemplo, usando knockoutjs). En ese caso, la ordenación del controlador de eventos puede causar algunos problemas. Por lo tanto, implementé enlaces deshabilitados vinculando un retorno falsa controlador de enlace del touchstart, mousedowny keydowneventos. tiene algunos inconvenientes (que evitará que toque scrolling comenzó en el enlace)" , pero el manejo de eventos de teclado también tiene la ventaja de evitar la navegación por teclado.

Tenga en cuenta que si hrefno se borra, es posible que el usuario visite manualmente esa página.

Borrar el enlace

Borrar el hrefatributo Con este código no agrega un controlador de eventos, sino que cambia el enlace en sí. Use este código para deshabilitar los enlaces:

$("td > a").each(function() {
    this.data("href", this.attr("href"))
        .attr("href", "javascript:void(0)")
        .attr("disabled", "disabled");
});

Y este para volver a habilitarlos:

$("td > a").each(function() {
    this.attr("href", this.data("href")).removeAttr("disabled");
});

Personalmente, no me gusta mucho esta solución (si no tiene que hacer más con los enlaces deshabilitados), pero puede ser más compatible debido a varias formas de seguir un enlace.

Controlador de clic falso

Agregue / elimine una onclickfunción donde no se return falseseguirá el enlace. Para deshabilitar enlaces:

$("td > a").attr("disabled", "disabled").on("click", function() {
    return false; 
});

Para volver a habilitarlos:

$("td > a").removeAttr("disabled").off("click");

No creo que haya una razón para preferir esta solución en lugar de la primera.

Estilo

El estilo es aún más simple, independientemente de la solución que esté utilizando para deshabilitar el enlace, agregamos un disabledatributo para que pueda usar la siguiente regla CSS:

a[disabled] {
    color: gray;
}

Si está utilizando una clase en lugar de un atributo:

a.disabled {
    color: gray;
}

Si está utilizando un marco de interfaz de usuario, puede ver que los enlaces deshabilitados no tienen el estilo adecuado. Bootstrap 3.x, por ejemplo, maneja este escenario y el botón tiene el estilo correcto tanto con disabledatributo como con .disabledclase. Si, en cambio, está borrando el enlace (o está utilizando una de las otras técnicas de JavaScript), también debe manejar el estilo porque un <a>sin hreftodavía se pinta como habilitado.

Aplicaciones de Internet enriquecidas accesibles (ARIA)

No olvide incluir también un atributo aria-disabled="true"junto con disabledatributo / clase.

Adriano Repetti
fuente
2
Correcto. Pero para facilitar el mantenimiento, agregaría controladores de eventos de clic a todos td alos mensajes de correo electrónico que podrían estar deshabilitados, que llamarán event.preventDefault()si $(this).data('disabled')es verdadero y luego establecerán data('disabled', true)cualquier enlace que quiera deshabilitar (falso para habilitar, etc.)
ori
1
@Ankit ¡Por apariencia tienes CSS! Configure una regla para enlaces 'deshabilitados' como este a [deshabilitado] {color: gris}
Adriano Repetti
1
Actualización rápida en soporte de navegador . Tenga en cuenta que aunque IE11 admite eventos de puntero, hay un pequeño tidbit que dice que no funciona en los enlaces: (...
agosto
1
$(this).is('[disabled]')podría ser una mejor manera de detectar el atributo deshabilitado
Dave Stewart
2
Jon, no me gusta mucho. En primer lugar porque la navegación del teclado todavía funciona. Segundo, porque es un truco (puede ser útil solo si nada más funciona). Tercero, porque algunas personas mantienen Javascript desactivado y en este caso no tienes ningún "nivel" de protección. Cuarto porque es la solución más complicada aquí (cuando algunas líneas Javascript pueden funcionar)
Adriano Repetti
23

Tengo la solución en CSS.

td.disabledAnchor a{
       pointer-events: none !important;
       cursor: default;
       color:Gray;
}

Por encima de css cuando se aplica a la etiqueta de anclaje, se deshabilitará el evento de clic.

Para más detalles, consulte este enlace

Ankit
fuente
1
Es una buena solución, pero no es compatible con ... supongo ... Internet Explorer.
Adriano Repetti
Es compatible con todos los navegadores
Ankit
1
No debería ser compatible con HTML en Internet Explorer y Opera.
Adriano Repetti
@Ankit, no funciona en IE 9 y versiones inferiores. ¿Estás usando IE 10?
Mandeep Jain
44
Esto falla el caso de uso de eventos de teclado como Adriano Repetti menciona anteriormente. El usuario aún puede tabular el enlace y presionar enter.
Jaula de cascabel
12

Gracias a todos los que publicaron soluciones (especialmente @AdrianoRepetti), combiné varios enfoques para proporcionar una disabledfuncionalidad más avanzada (y funciona en varios navegadores). El código está debajo (tanto ES2015 como coffeescript según su preferencia).

Esto proporciona múltiples niveles de defensa para que las Anclas marcadas como deshabilitadas realmente se comporten como tales. Con este enfoque, obtienes un ancla que no puedes:

  • hacer clic
  • pestaña y presione regresar
  • tabularlo moverá el foco al siguiente elemento enfocable
  • sabe si el ancla se habilita posteriormente

Cómo

  1. Incluya este CSS, ya que es la primera línea de defensa. Esto supone que el selector que usa esa.disabled

    a.disabled {
      pointer-events: none;
      cursor: default;
    }
  2. A continuación, cree una instancia de esta clase en lista (con selector opcional):

      new AnchorDisabler()

Clase ES2015

npm install -S key.js

import {Key, Keycodes} from 'key.js'

export default class AnchorDisabler {
  constructor (config = { selector: 'a.disabled' }) {
    this.config = config
    $(this.config.selector)
      .click((ev) => this.onClick(ev))
      .keyup((ev) => this.onKeyup(ev))
      .focus((ev) => this.onFocus(ev))
  }

  isStillDisabled (ev) {
    //  since disabled can be a class or an attribute, and it can be dynamically removed, always recheck on a watched event
    let target = $(ev.target)
    if (target.hasClass('disabled') || target.prop('disabled') == 'disabled') {
      return true
    }
    else {
      return false
    }
  }

  onFocus (ev) {
    //  if an attempt is made to focus on a disabled element, just move it along to the next focusable one.
    if (!this.isStillDisabled(ev)) {
      return
    }

    let focusables = $(':focusable')
    if (!focusables) {
      return
    }

    let current = focusables.index(ev.target)
    let next = null
    if (focusables.eq(current + 1).length) {
      next = focusables.eq(current + 1)
    } else {
      next = focusables.eq(0)
    }

    if (next) {
      next.focus()
    }
  }

  onClick (ev) {
    // disabled could be dynamically removed
    if (!this.isStillDisabled(ev)) {
      return
    }

    ev.preventDefault()
    return false
  }

  onKeyup (ev) {
    // We are only interested in disabling Enter so get out fast
    if (Key.isNot(ev, Keycodes.ENTER)) {
      return
    }

    // disabled could be dynamically removed
    if (!this.isStillDisabled(ev)) {
      return
    }

    ev.preventDefault()
    return false
  }
}

Clase de Coffescript:

class AnchorDisabler
  constructor: (selector = 'a.disabled') ->
    $(selector).click(@onClick).keyup(@onKeyup).focus(@onFocus)

  isStillDisabled: (ev) =>
    ### since disabled can be a class or an attribute, and it can be dynamically removed, always recheck on a watched event ###
    target = $(ev.target)
    return true if target.hasClass('disabled')
    return true if target.attr('disabled') is 'disabled'
    return false

  onFocus: (ev) =>
    ### if an attempt is made to focus on a disabled element, just move it along to the next focusable one. ###
    return unless @isStillDisabled(ev)

    focusables = $(':focusable')
    return unless focusables

    current = focusables.index(ev.target)
    next = (if focusables.eq(current + 1).length then focusables.eq(current + 1) else focusables.eq(0))

    next.focus() if next


  onClick: (ev) =>
    # disabled could be dynamically removed
    return unless @isStillDisabled(ev)

    ev.preventDefault()
    return false

  onKeyup: (ev) =>

    # 13 is the js key code for Enter, we are only interested in disabling that so get out fast
    code = ev.keyCode or ev.which
    return unless code is 13

    # disabled could be dynamically removed
    return unless @isStillDisabled(ev)

    ev.preventDefault()
    return false
kross
fuente
Pero, ¿qué sucede si necesitamos una solución jQuery / javascript directa? Vea mi respuesta a continuación.
Jon Crawford
1
Bueno, entonces usas la clase ES2015 que acabo de agregar.
kross
7

Prueba el elemento:

$(td).find('a').attr('disabled', 'disabled');

Deshabilitar un enlace me funciona en Chrome: http://jsfiddle.net/KeesCBakker/LGYpz/ .

Firefox no parece jugar bien. Este ejemplo funciona:

<a id="a1" href="http://www.google.com">Google 1</a>
<a id="a2" href="http://www.google.com">Google 2</a>

$('#a1').attr('disabled', 'disabled');

$(document).on('click', 'a', function(e) {
    if ($(this).attr('disabled') == 'disabled') {
        e.preventDefault();
    }
});

Nota: se agregó una declaración 'en vivo' para futuros enlaces deshabilitados / habilitados.
Nota 2: cambió 'live' a 'on'.

Kees C. Bakker
fuente
66
El nuevo ejemplo también debería funcionar en Firefox. ;-) es una solución: D
Kees C. Bakker
Chrome impide la navegación en jsFiddle debido a "Se negó a mostrar el documento porque la visualización está prohibida por X-Frame-Options". Lo siento si el ejemplo de jsfiddle hace cosas raras ;-)
Kees C. Bakker
Tengo que mostrar la etiqueta de anclaje como deshabilitada también. Igual que se muestra en IE. Además, no quiero modificar la función de clic para marcar si está deshabilitada
Ankit
El show-part puede hacerse mediante css y agregando una clase que lo haga gris. La ventaja del clic 'en vivo' es que solucionará el problema de todos los enlaces. Si puedo ayudar más, solo házmelo saber. Espero que tengas éxito.
Kees C. Bakker
¡Pruebe mi respuesta a continuación para obtener una solución de navegador completamente cruzado!
Jon Crawford
4

Bootstrap 4.1 proporciona una clase con nombre disabledy aria-disabled="true"atributo.

ejemplo"

<a href="#" 
        class="btn btn-primary btn-lg disabled" 
        tabindex="-1" 
        role="button" aria-disabled="true"
>
    Primary link
</a>

Más está en getbootstrap.com

Entonces, si desea hacerlo dinámicamente, y you don't want to care if it is button or ancorque en el script JS necesita algo así

   let $btn=$('.myClass');
   $btn.attr('disabled', true);
   if ($btn[0].tagName == 'A'){
        $btn.off();
        $btn.addClass('disabled');
        $btn.attr('aria-disabled', true);
   }

Pero ten cuidado

La solución solo funciona en enlaces con clases btn btn-link.

A veces, bootstrap recomienda usar card-linkclass, en este caso la solución no funcionará .

Yevgeniy Afanasyev
fuente
1

Terminé con la solución a continuación, que puede funcionar con un atributo <a href="..." disabled="disabled">o una clase <a href="..." class="disabled">:

Estilos CSS:

a[disabled=disabled], a.disabled {
    color: gray;
    cursor: default;
}

a[disabled=disabled]:hover, a.disabled:hover {
    text-decoration: none;
}

Javascript (en jQuery listo):

$("a[disabled], a.disabled").on("click", function(e){

    var $this = $(this);
    if ($this.is("[disabled=disabled]") || $this.hasClass("disabled"))
        e.preventDefault();
})
isapir
fuente
0

no se puede deshabilitar un enlace, si quieres ese evento de clic no debe disparar a continuación, simplemente Removela actionde ese enlace.

$(td).find('a').attr('href', '');

Para más información: - Elementos que se pueden deshabilitar

Pranav
fuente
1
Esto realmente no deshabilita el enlace. El elemento de anclaje seguirá disparándose, aunque permanecerá en la misma página.
Florian Margaine
0

Haría algo como

$('td').find('a').each(function(){
 $(this).addClass('disabled-link');
});

$('.disabled-link').on('click', false);

Algo como esto debería funcionar. Agrega una clase para los enlaces que desea deshabilitar y luego devuelve falso cuando alguien hace clic en ellos. Para habilitarlos simplemente elimine la clase.

mkk
fuente
Esto no ayudaría. Tengo que volver a registrar el evento click y la función es dinámica que se llama. Una vez eliminado, no puedo volver a asociarlo
Ankit
0

Para deshabilitar el enlace para acceder a otra página en el dispositivo táctil:

if (control == false)
  document.getElementById('id_link').setAttribute('href', '#');
else
  document.getElementById('id_link').setAttribute('href', 'page/link.html');
end if;
rgfpy
fuente
Mi respuesta también funciona en dispositivos móviles. Muy cruzado navegador. Vea abajo.
Jon Crawford
Esto está mal, si usted setAttribute('href', '');y la URL de la página es http://example.com/page/?query=somethingel enlace al hacer clic en IE11 iría a http://example.com/page/. Una solución podría ser usarsetAttribute('href', '#');
Marco Demaio
0

En Razor (.cshtml) puedes hacer:

@{
    var isDisabled = true;
}

<a href="@(isDisabled ? "#" : @Url.Action("Index", "Home"))" @(isDisabled ? "disabled=disabled" : "") class="btn btn-default btn-lg btn-block">Home</a>
Joel Wiklund
fuente
-2

Puede usar esto para deshabilitar el hipervínculo de asp.net o los botones de enlace en html.

$("td > a").attr("disabled", "disabled").on("click", function() {
    return false; 
});
Mitesh
fuente
-2

Hay otra forma posible, y la que más me gusta. Básicamente, es la misma forma en que lightbox desactiva una página completa, colocando un div y jugando con el índice z. Aquí hay fragmentos relevantes de un proyecto mío. ¡Esto funciona en todos los navegadores!

Javascript (jQuery):

var windowResizer = function(){
        var offset = $('#back').offset();   
        var buttontop = offset.top;
        var buttonleft = offset.left;
        $('#backdisabler').css({'top':buttontop,'left':buttonleft,'visibility':'visible'});
        offset = $('#next').offset();
        buttontop = offset.top;
        buttonleft = offset.left;
        $('#nextdisabler').css({'top':buttontop,'left':buttonleft,'visibility':'visible'});
}

$(document).ready(function() {
    $(window).resize(function() {   
        setTimeout(function() {
            windowResizer();
        }, 5); //when the maximize/restore buttons are pressed, we have to wait or it will fire to fast
    });
});

y en html

<a href="" id="back" style="float: left"><img src="images/icons/back.png" style="height: 50px; width: 50px" /></a>
<a href="" id="next" style="float: right"><img src="images/icons/next.png" style="height: 50px; width: 50px" /></a>
<img id="backdisabler" src="images/icons/disabled.png" style="visibility: hidden; position: absolute; padding: 5px; height: 62px; width: 62px; z-index: 9000"/>
<img id="nextdisabler" src="images/icons/disabled.png" style="visibility: hidden; position: absolute; padding: 5px; height: 62px; width: 62px; z-index: 9000"/>

Entonces, el redimensionador encuentra las ubicaciones del ancla (las imágenes son solo flechas) y coloca el desactivador en la parte superior. La imagen del desactivador es un cuadrado gris translúcido (cambie el ancho / alto de los desactivadores en el html para que coincida con su enlace) para mostrar que está desactivado. El flotante permite que la página cambie de tamaño dinámicamente, y los desactivadores seguirán su ejemplo en windowResizer (). Puede encontrar imágenes adecuadas a través de google. He colocado el css relevante en línea para simplificar.

luego basado en alguna condición,

$('#backdisabler').css({'visibility':'hidden'});
$('#nextdisabler').css({'visibility':'visible'});
Jon Crawford
fuente
44
No voté negativamente, pero supongo: demasiada sobrecarga para algo simple, su código no está lo suficientemente comentado para una respuesta en SO. También se siente muy hacky, personalmente no usaría eso.
Emile Bergeron
-5

Creo que muchos de estos han terminado de pensar. Agrega una clase de lo que quieras, como disabled_link.
Luego, haga que css tenga .disabled_link { display: none }
Boom ahora, el usuario no puede ver el enlace para que no tenga que preocuparse de que hagan clic en él. Si hacen algo para satisfacer el enlace de ser puede hacer clic, basta con quitar la clase con jQuery:
$("a.disabled_link").removeClass("super_disabled"). ¡Auge hecho!

Jordan Michael Rushing
fuente
De la pregunta: "Y DEBO MOSTRAR EL ENLACE EN MODO DESACTIVADO".
Marcelo
Sí, tienes razón. Me lo perdí. Entonces, en su lugar, diría que mueva el valor de href a data-href. $("td a").each(function(i,v){ $(this).data('href',this.href); $(this).attr('href','#').css('color','grey'); });Entonces, cuando desee deshacerse de uno: $(this).attr('href',$(this).data('href')).css('color','blue');
Jordan Michael Rushing