[譯] 如何禁用連結:從入門到放棄

dearpork發表於2017-12-04

禁用連線:從入門到放棄

有一天,我在工作中產生了關於如何禁用連結的思考。不知為何,去年我無意新增了一個「disabled」錨點樣式。但有一個問題:你無法在 HTML 中真正禁用 <a> 連結(擁有合法 href 屬性)。更何況,你為什麼要禁用它呢?連結是 Web 的基礎。

某種意義上,我的同事看起來並不打算接受這個事實,所以我開始思考如何真正實現它。我知道這將付出很多努力,所以我想證明為了這種非傳統的互動並不值得付出努力和程式碼。但我擔心一旦被證明這是可以實現的,他們將無視我的警告繼續做類似的嘗試。這還沒有動搖我,不過我覺得我們可以開始看我的研究了。

第一:

不要這樣做。

一個被禁用的連結不能稱作一個連結,它只是一段文字。如果需要禁用一個連結的話,你需要重新思考你的設計。

Bootstrap 有一個為錨點標籤新增 .disabled 類的例子,我很討厭這點。雖然他們至少提及了這個類只提供了一個禁用 樣式,但這仍然是一種誤導。如果你真的想禁用一個連結,你需要做更多的工作而不是隻是讓它 看起來 被禁用了。

萬無一失的辦法:移除 href 屬性

如果你決定無視我的警告嘗試禁用一個連結,那麼 移除 href 屬性是我所知的最好的辦法

官方解釋 Hyperlink spec

aarea 元素的 href 屬性不是必要的;當這些元素沒有 href 屬性時,它們將不會解釋成超連結。

一個更易理解的定義 MDN

這個屬性可以被忽略(從 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 屬性。

那麼鍵盤使用者呢?鍵盤使用者會使用Enter鍵啟用連結。pointer-events 只用於游標,沒有鍵盤事件。我們還需要防止不支援 pointer-events 的舊瀏覽器啟用連結,現在我們將介紹一些 JavaScript。

引入 JavaScript

// 在用常用方法獲取連結之後
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;  /* 為了 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前端後端區塊鏈產品設計人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章