[译] 如何禁用连接:从入门到放弃

禁用链接:从入门到放弃

有一天,我在工做中产生了关于如何禁用连接的思考。不知为什么,去年我无心添加了一个「disabled」锚点样式。但有一个问题:你没法在 HTML 中真正禁用 <a> 连接(拥有合法 href 属性)。更况且,你为何要禁用它呢?连接是 Web 的基础。css

某种意义上,个人同事看起来并不打算接受这个事实,因此我开始思考如何真正实现它。我知道这将付出不少努力,因此我想证实为了这种非传统的交互并不值得付出努力和代码。但我担忧一旦被证实这是能够实现的,他们将无视个人警告继续作相似的尝试。这尚未动摇我,不过我以为咱们能够开始看个人研究了。html

第一:前端

不要这样作。

一个被禁用的连接不能称做一个连接,它只是一段文本。若是须要禁用一个连接的话,你须要从新思考你的设计。html5

Bootstrap 有一个为锚点标签添加 .disabled 类的例子,我很讨厌这点。虽然他们至少说起了这个类只提供了一个禁用 样式,但这仍然是一种误导。若是你真的想禁用一个连接,你须要作更多的工做而不是只是让它 看起来 被禁用了。node

万无一失的办法:移除 href 属性

若是你决定无视个人警告尝试禁用一个连接,那么 移除 href 属性是我所知的最好的办法android

官方解释 Hyperlink specios

aarea 元素的 href 属性不是必要的;当这些元素没有 href 属性时,它们将不会解释成超连接。git

一个更易理解的定义 MDNgithub

这个属性能够被忽略(从 HTML5 开始支持)以建立一个占位符连接。占位符连接相似传统的超连接,但它不会跳转到任何地方。后端

下面是用来设置和移除 href 属性的基本 JavaScript 代码:

/* 
 * 用你习惯的方式选择一个连接
 *
 * document.getElementById('MyLink');
 * document.querySelector('.link-class');
 * document.querySelector('[href="https://unfetteredthoughts.net"]');
 */
// 经过移除 href 属性来「禁用」一个连接。
link.href = '';
// 经过设置 href 属性启用连接
link.href = 'https://unfetteredthoughts.net';
复制代码

为这些连接设置 CSS 样式一样很是简单:

a {
  /* 已禁用的连接样式 */
}
a:link, a:visited { /* or a[href] */
  /* 可访问的连接样式 */
}
复制代码

这就是你所要作的所有!

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

若是你不得不为了某些极端状况过分设计,这里有些事情须要考虑。但愿你注意而且意识到我将为你展现的东西并不值得为之努力。

首先,咱们须要为连接添加样式,让它看起来被禁用了。

.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,这样鼠标悬停时就会显示禁用的标识。咱们遗漏掉了那些不使用鼠标的用户,他们主要使用触摸和键盘,因此并不会获得这个指示。接下来,将透明度减至 0.5。根据 WCAG,禁用的元素不须要知足颜色对比指南。我认为这是很危险的,由于这基本上是纯文本,减小透明度至 0.5 将使视弱用户难以阅读,这是我讨厌禁用连接的另外一个缘由。最后,文本的下划线被移除了,由于它一般是一个连接的最佳标识。如今,这 看起来 是一个被禁用的连接了!

但它并无被真正禁用!用户仍然能够点击、触摸这个连接。我听到你在尖叫 pointer-events

.isDisabled {
  ...
  pointer-events: none;
}
复制代码

如今,咱们完成了全部工做!禁用一个连接已经大功告成!虽然这只是对鼠标用户和触屏用户 真正地 禁用了连接。那么对于不支持 pointer-events 的浏览器怎么办呢?根据 caniuse,Opera Mini 以及 IE 11 如下版本都不支持这个属性。IE 11 以及 Edge 实际上也不支持 pointer-events,除非 display 设置成 block 或者 inline-block。并且,将 pointer-events 设置成 none 将覆盖咱们 not-allowed 的指针样式,因此如今鼠标用户将不会获得这个额外的视觉指示,代表连接被禁用。这已经开始崩溃了。如今咱们不得不更改咱们的标记和 CSS。

.isDisabled {
  cursor: not-allowed;
  opacity: 0.5;
}
.isDisabled > a {
  color: currentColor;
  display: inline-block;  /* 为了 IE11/ MS Edge 的 bug */
  pointer-events: none;
  text-decoration: none;
}
复制代码
<span class="isDisabled"><a href="https://unfetteredthoughts.net">Disabled Link</a></span>
复制代码

将一个连接包裹在 <span> 标签中并添加 isDisabled 类给了咱们一半禁用视觉样式。一个很好的效果是这个 isDisabled 类是通用的,能够用在其余元素上,例如按钮和表单元素。实际的锚点标签如今有设置为 nonepointer-eventstext-decoration 属性。

那么键盘用户呢?键盘用户会使用回车键激活连接。pointer-events 只用于光标,没有键盘事件。咱们还须要防止不支持 pointer-events 的旧浏览器激活连接,如今咱们将介绍一些 JavaScript。

引入 JavaScript

// 在用经常使用方法获取连接以后
link.addEventListener('click', function (event) {
  if (this.parentElement.classList.contains('isDisabled')) {
    event.preventDefault();
  }
});
复制代码

如今咱们的连接 看起来 被禁用了并且不会响应点击、触摸以及回车键。可是咱们还没完成!屏幕阅读器用户没法知道这个连接已经被禁用了。咱们须要将这个连接描述为被禁用。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;  /* 为了 IE11/ MS Edge 的 bug */
  pointer-events: none;
  text-decoration: none;
}
复制代码

如今咱们的连接 看起来 被禁用, 表现起来 被禁用, 并且被 描述 成被禁用.

不幸的是,即使连接被描述成被禁用,一些屏幕阅读器(JAWS)仍将宣称这些连接是可点击的。任何一个有点击事件监听器的元素都是这样。这是由于开发者倾向于将非交互元素如 divspan 添加事件监听器从而当作伪交互元素使用。对此咱们无能为力。咱们为了去除一个连接的全部特征所作的努力都被咱们想要愚弄的辅助技术所挫败,讽刺的是,咱们以前就想骗过它了。

不过,若是咱们将监听器移动到 body 呢?

document.body.addEventListener('click', function (event) {
  // 过滤掉其余元素的点击事件
  if (event.target.nodeName == 'A' && event.target.getAttribute('aria-disabled') == 'true') {
    event.preventDefault();
  }
});
复制代码

咱们完成了吗?其实并无。有的时候咱们须要启用这些连接,因此咱们须要添加额外的代码来切换这些状态或行为。

function disableLink(link) {
// 1\. 为父级 span 添加 isDisabled 类
  link.parentElement.classList.add('isDisabled');
// 2\. 保存 href 以便之后添加
  link.setAttribute('data-href', link.href);
// 3\. 移除 href
  link.href = '';
// 4\. 设置 aria-disabled 为 'true'
  link.setAttribute('aria-disabled', 'true');
}
function enableLink(link) {
// 1\. 将父级 span 的 'isDisabled' 类移除
  link.parentElement.classList.remove('isDisabled');
// 2\. 设置 href
  link.href = link.getAttribute('data-href');
// 3\. 移除 'aria-disabled' 属性,比将其设为 false 更好
  link.removeAttribute('aria-disabled');
}
复制代码

就是这样。咱们如今从视觉上、功能上以及语义上为全部的用户禁用了连接。它只用了 10 行 CSS,15 行 JavaScript(包括 body 上的一个监听器)以及 2 个 HTML 元素。

说真的,不要作这样的尝试。


掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 AndroidiOS前端后端区块链产品设计人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划官方微博知乎专栏

相关文章
相关标签/搜索