如何禁用链接

Avatar of Gerard Cohen
Gerard Cohen

DigitalOcean 为您旅程的每个阶段提供云产品。立即开始使用 200 美元的免费积分!

禁用链接的话题前几天在我的工作中出现了。不知何故,去年在我没注意的时候,一个“禁用”锚点样式被添加到我们的排版样式中。但是,存在一个问题:在 HTML 中没有真正的方法可以禁用 <a> 链接(具有有效的 href 属性)。更不用说,你为什么要这样做?链接是网络的基础。

在某个时刻,我的同事似乎并不接受这个事实,所以我开始思考如何才能实现这一点。知道这需要付出很多努力,我想证明它不值得付出努力和代码来支持这种非常规的交互,但我担心通过展示它可以做到,他们会忽略我所有的警告,并只使用我的例子作为证明这样做是可以的。这件事对我来说还没有完全明朗,但我认为我们可以回顾一下我的研究。

首先,第一件事

不要这样做。

禁用的链接不是链接,它只是文本。如果你的设计需要禁用链接,你需要重新考虑你的设计。

Bootstrap 有将 .disabled 类应用于锚标记的示例,我为此讨厌它们。至少他们提到该类仅提供禁用的样式,但这具有误导性。如果你真的想禁用链接,你需要做的不仅仅是让它看起来已禁用。

万无一失的方法:移除 href

如果你决定忽略我的警告并继续禁用链接,那么删除 href 属性是我所知最好的方法

来自官方的 超链接规范

aarea 元素上的 href 属性不是必需的;当这些元素没有 href 属性时,它们不会创建超链接。

来自 MDN 的更容易理解的定义

此属性可以省略(从 HTML5 开始)以创建占位符链接。占位符链接类似于传统的超链接,但不会指向任何位置。

这是一个设置和移除 href 属性的基本 JavaScript 代码

/* 
 * 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';

通过 CSS 对其进行样式设置也很简单

a {
  /* Disabled link styles */
}
a:link, a:visited { /* or a[href] */
  /* Enabled link styles */
}

这就是你需要做的!

这还不够,我想要更复杂的东西,这样我看起来更聪明!

如果你必须过度设计一些极端的解决方案,这里有一些需要考虑的事情。希望你会注意并认识到我即将向你展示的内容不值得付出努力。

首先,我们需要为我们的链接设置样式,使其看起来已禁用。

.isDisabled {
  color: currentColor;
  cursor: not-allowed;
  opacity: 0.5;
  text-decoration: none;
}
<a class="isDisabled" href="https://unfetteredthoughts.net">Disabled Link</a>

color 设置为 currentColor 应该将字体颜色重置回你的正常非链接文本颜色。我还将鼠标光标设置为 not-allowed 以在悬停时显示一个很好的指示器,表明不允许进行正常操作。我们已经排除了无法悬停的非鼠标用户,主要是触摸和键盘用户,因此他们不会获得此指示。接下来,不透明度降低到一半。根据 WCAG,禁用的元素不需要满足颜色对比度指南。我认为这非常冒险,因为它此时基本上是纯文本,并且将不透明度降低一半会使视力低下用户的阅读变得非常困难,这是我讨厌它的另一个原因。最后,删除文本修饰下划线,因为这通常是表明某物是链接的最佳指示器。现在这看起来像一个禁用的链接!

但它实际上并没有禁用!用户仍然可以点击/点击此链接。我听到你在大喊 pointer-events

.isDisabled {
  ...
  pointer-events: none;
}

好了,我们完成了!禁用的链接实现了!除了,它真正只对点击的鼠标用户和点击的触摸用户禁用。不支持 pointer-events 的浏览器呢?根据 caniuse,Opera Mini 和 IE<11 不支持此功能。IE11 和 Edge 实际上不支持 pointer-events,除非 display 设置为 blockinline-block。此外,将 pointer-events 设置为 none 会覆盖我们漂亮的 not-allowed 光标,因此现在鼠标用户不会获得该链接已禁用的额外视觉指示。这已经开始瓦解了。现在我们必须更改我们的标记和 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>

将链接包装在 <span> 中并添加 isDisabled 类为我们提供了禁用视觉样式的一半。这里一个不错的副作用是,禁用类现在是通用的,可以用于其他元素,如按钮和表单元素。实际的锚标记现在将 pointer-eventstext-decoration 设置为 none

键盘用户怎么办?键盘用户将使用 ENTER 键激活链接。pointer-events 仅适用于指针,没有键盘事件。我们还需要阻止不支持 pointer-events 的旧版浏览器的激活。现在我们必须引入一些 JavaScript。

引入 JavaScript

// After using preferred method to target link
link.addEventListener('click', function (event) {
  if (this.parentElement.classList.contains('isDisabled')) {
    event.preventDefault();
  }
});

现在我们的链接看起来已禁用,并且不会响应点击、点击和 ENTER 键的激活。但我们还没有完成!屏幕阅读器用户无法知道此链接已禁用。我们需要将此链接描述为已禁用。disabled 属性在链接上无效,但我们可以使用 aria-disabled="true"

<span class="isDisabled"><a href="https://unfetteredthoughts.net" aria-disabled="true">Disabled Link</a></span>

现在我将借此机会根据 aria-disabled 属性设置链接的样式。我喜欢将 ARIA 属性用作 CSS 的钩子,因为元素样式不正确是表明重要的辅助功能缺失的指标。

.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;
}

现在我们的链接看起来已禁用、行为已禁用,并且被描述为已禁用。

不幸的是,即使链接被描述为已禁用,一些屏幕阅读器(JAWS)仍然会将其宣布为可点击的。它对任何具有点击侦听器的元素都这样做。这是因为开发人员倾向于将非交互式元素(如 divspan)作为具有简单侦听器的伪交互式元素。我们在这里无能为力。我们为删除任何表明这是链接的指示而做的一切都被我们试图欺骗的辅助技术所破坏,具有讽刺意味的是,因为我们之前曾试图欺骗它。

但是如果我们将侦听器移动到主体怎么办?

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();
  }
});

我们完成了吗?好吧,还没有。在某个时候,我们需要启用这些链接,因此我们需要添加其他代码来切换此状态/行为。

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');
}

就是这样。我们现在有一个禁用的链接,对于所有用户来说,它在视觉上、功能上和语义上都已禁用。它只需要 10 行 CSS、15 行 JavaScript(包括主体上的 1 个侦听器)和 2 个 HTML 元素。

说真的,朋友们,不要这样做。