[譯] 在網頁中隱藏元素

原文連接:Hiding Elements On The Web,by Ahmad Shadeedjavascript

在平時的開發工做中,有時會有隱藏元素的需求。好比,一個按鈕,須要在桌面端隱藏,在手機端顯示;一個導航欄,須要在手機端隱藏,在桌面端顯示。「隱藏」不是字面上展現的這樣簡單,它還包含幾層意思:css

  • 元素徹底從文檔流中移除的隱藏。
  • 元素僅僅是視覺上的隱藏,使用像屏幕閱讀器(screen reader)這樣的輔助技術(assistive technology,簡稱「AT」)依然是能訪問的。
  • 元素在視覺上可見,不過對屏幕閱讀器是隱藏的,即屏幕閱讀器是沒法訪問的。

經過本篇文章,你將會學到利用 HTML/CSS 隱藏元素的方法,內容涵蓋了可訪問性、動畫和使用案例。咱們一塊兒來看看吧!html

HTML5 hidden 屬性

這是在 HTML 標籤上使用的一個布爾值屬性。在瀏覽器加載頁面的時候,使用 hidden 屬性修飾的元素,渲染效果與 display: none 相似。固然,若是使用 CSS 手動重寫了 hidden 屬性的話,就另當別論了。java

來看下面的例子:web

這部分包含了一個標題、圖片和描述信息。圖片只會在視口寬度大於 400px 的時候才顯示。這裏我給 <img> 加了一個 hidden 屬性。瀏覽器

我寫了一段 CSS 代碼,讓 hidden 屬性修飾的圖片在視口寬度大於 400px 的時候顯示。svg

img[hidden] {
  display: none;
}

@media (min-width: 400px) {
  img[hidden] {
    display: block;
  }
}
複製代碼

下面是在大視口(大於 400px)下的渲染效果。工具

Demo學習

你可能要問了,爲何不直接使用 display: none 呢?好問題。圖片使用 hidden 屬性控制帶來的好處是——即便 CSS 因爲某種緣由沒有加載成功,圖片也會隱藏。測試

hidden 屬性對可訪問性的影響

hidden 會將元素徹底從頁面隱藏,因此屏幕閱讀器是沒法訪問。若是隻是出於視覺表現的目的,必定要避免使用。

CSS display 屬性

每一個元素都有一個默認的 display 值,多是 inline-blockblocktable 等等。咱們使用 display: none 就能達到隱藏元素的效果,而且該元素的全部後代都和它一塊兒隱藏了。

與上面代碼相似,不過此次咱們使用了 display: none

img {
  display: none;
}

@media (min-width: 400px) {
  img {
    display: block;
  }
}
複製代碼

display: none 會將元素從文檔流中移除,屏幕閱讀器也是沒法訪問到。那麼,什麼是文檔流?咱們能夠用下面的圖片來生動地描述它:

咱們把藍皮書用 display: none 隱藏了,最後發現它從這摞書裏徹底消失了,就好像被抽走了同樣。藍皮書原來佔據的空間不存在了。HTML 於此相似,說明文檔流被改變了。

下面的動畫,展現了藍皮書被移除時的情況:

stack-of-books.gif

圖片隱藏後,還會加載嗎?

會的。舉個例子,<img> 默認使用 CSS 隱藏,咱們將它設置在某個斷點處顯示。咱們打開 DevTools,檢查 networks 選項卡,仍是發現圖像被加載了,即便沒有顯示。

Demo

<style> 元素

值得一提的是,某些元素默認就是 display: none 的。好比 <style> 。咱們能夠把插入到 HTML 頁面中的 <style>display 值設置爲 block,這樣就能看見它了。

<body>
    <style> .title { color: #000; } </style>
</body>
複製代碼
style {
    display: block;
}
複製代碼

這事若是在讓樣式塊(style block)變得可編輯,就更有趣了。能夠經過爲 <style> 添加 contenteditable 屬性來實現。

style-tag.gif

Demo(譯註:在 Firefox 中能看到上面的效果,而在 Chrome 裏是看不到的)

display:none 對可訪問性的影響

hidden 屬性同樣,display: none 元素也是從頁面中徹底隱藏的,屏幕閱讀器也沒法訪問。

opacity

元素設置 opacity 後,包括後代都會被隱藏,這不是由於繼承的緣由。然而,這只是視覺上的隱藏。還要注意的是,opacity 值小於 1 的元素會建立一個 層疊上下文


上圖裏,藍皮書只是在視覺上隱藏了。它所佔據的空間仍然保留,與 display: none 效果比較的話,這一摞書的順序沒有發生變化。

img {
    opacity: 0;
}
複製代碼

咱們把最開始的例子,用 opacity: 0 從新改寫下,結果會是這樣的:

圖片從視覺上隱藏了,但它佔據空間依然是在的。

Dusan Milovanovic 指出,pointer-events: none | auto 能夠用來禁用使用 opacity: 0 隱藏的元素上的鼠標事件。這仍是很重要的,若是一個元素看不見了,但依然能響應用戶的點擊、懸停或選擇文本的行爲,勘定是很奇怪的。

Demo

opacity: 0 對可訪問性的影響

使用 opacity: 0 隱藏的元素依然能被屏幕閱讀器訪問,也能被鍵盤聚焦。

visibility

使用 visibility: hidden 的隱藏元素與使用 opacity: 0 的元素相似,不影響視覺上的文檔流表現。

請注意,藍皮書從可視流中隱藏了,但並無影響這摞書的順序。

有一點,若是 visibility: hidden 是在父元素身上使用,那麼它及其它的後代默認都是看不見的。可是,若是有一個子元素上使用了 visibility: hidden,那麼這子元素將是可見的。

<article>
  <h1>Spring is on the way</h1>
  <img src="landscape.jpg" alt="">
  <p><!-- Desc --></p>
</article>
複製代碼
article {
    visibility: hidden;
}

img {
    visibility: visible;
}
複製代碼

visibility-child.gif

上例中,<article> 使用了 visibility: hidden,而子元素 <img>visibility: visible 的,結果圖片依然是顯示的。也就是說,子元素是能夠重寫父元素的 visibility 屬性的。

Demo

visibility: hidden 對可訪問性的影響

若是一個元素 visibility: hidden 了,那麼它以及它的全部後代元素都會從訪問樹(accessibility tree)中刪除,不會被屏幕閱讀器讀到。

CSS position 屬性

使用 position 屬性將隱藏元素的原理,就是把元素移動到屏幕以外,設置其尺寸爲 0 (寬和高)。好比,網頁裏 跳過導航(skip navigation) 連接:

爲了讓連接定位到屏幕以外,咱們能夠這麼作:

.skip-link {
    position: absolute;
    top: -100%;
}
複製代碼

-100% 會將元素網上推出一個視口高度的距離。結果,連接就被徹底隱藏了。當連接被鍵盤聚焦時,則能夠這樣設置:

.skip-link:focus {
    position: absolute;
    top: 0;
}
複製代碼

Demo

position: absolute | fixed 對可訪問性的影響

元素能夠被屏幕閱讀器讀到,被鍵盤聚焦。只是移動到視口以外了而已。

clip-path

clip-path 屬性用來建立一個裁剪區域,只有在這個區域內的元素內容纔是可見的,其餘部分則是隱藏的。


上面的圖片通過裁剪,兩邊的透明黑色區域看不見了。

爲了用更直觀的方式演示,我使用 clippy 工具來解釋。在下面的 GIF 圖中,我定義了以下的 clip-path

img {
    clip-path: polygon(0 0, 0 0, 0 0, 0 0);
}
複製代碼

clip-path-1.gif

將多邊形每一個點的座標設置爲 (0, 0),則裁剪區域變爲 0。結果,圖像不會顯示了。一樣,還能夠用一個圓(circle)來代替這裏的多邊形(polygon):

img {
    clip-path: circle(0 at 50% 50%);
}
複製代碼

clip-path-2.gif

使用 clip-path 實現的隱形效果只是視覺上的,屏幕閱讀器依然能夠訪問,鍵盤也能聚焦。

Demo

操做 colorfont-size

儘管這兩種技術並不像咱們前面討論的那樣廣泛,但在某些場景下比較有用。

color: transparent

將文本設置成透明色(transparent),只是視覺上隱藏了。這比較適合僅帶圖標的按鈕。

font-size: 0

將文字大小設置爲 0 也是視覺上的隱藏。

來看一個包含以下結構的按鈕:

<button>
  <svg width="24" height="24" viewBox="0 0 24 24" aria-hidden="false" focusable="false">
    <!-- Path data -->
  </svg>
  <span>Like</span>
</button>
複製代碼

咱們的目標是以一種能被訪問的方式隱藏文本。爲此,我使用了下面的 CSS:

.button span {
    color: transparent;
    font-size: 0;
}
複製代碼

文本隱藏了。

Demo

aria-hidden

當爲元素添加 aria-hidden 後,就會從訪問樹中刪除,這能夠用來提高屏幕閱讀器用戶的體驗。須要注意的是,元素依然是視覺可見的。

<button>
    Menu
    <svg aria-hidden="true"><!-- --></svg>
</button>
複製代碼

這裏是一個帶 label 和圖表的菜單按鈕。爲了讓 svg 對屏幕閱讀器隱藏,這裏添加了 aria-hidden

根據 MDN 文檔,aria-hidden 的使用場景包括:

  • 用來隱藏修飾性內容,好比圖標、圖片。
  • 隱藏重複的文字。
  • 隱藏屏幕外的或摺疊的內容。

aria-hidden 是爲屏幕閱讀器設計的,所以它僅對屏幕閱讀器隱藏內容。可是,內容對於視覺用戶仍然可見,而且也支持鍵盤聚焦。

動畫和交互

速查表

在咱們開始示例以前,我想帶你們回顧一下前面提到的屬性,我從 CSS-tricks 上的 這篇文章 得到了靈感,作了下面的一張速查表,方便你們在使用時根據須要選擇合適的方法。

image.png

View on Codepen

當咱們想對隱藏元素使用動畫的時候。好比,顯示隱藏的移動導航,須要以一種可訪問的方式來實現。爲了得到訪問性體驗,咱們將探索一些值得學習的好例子,以及一些很差的例子,避免犯錯誤,從而給屏幕閱讀器用戶帶來更好的體驗。

菜單動畫 - 很差的例子

咱們有一個菜單,在展開時使用一個劃入的動畫。最簡單的作法是使用下面的方法:

ul {
    opacity: 0;
    transform: translateX(100%);
    transition: 0.3s ease-out;
}

ul.active {
    opacity: 1;
    transform: translateX(0);
}
複製代碼

根據這種方法,菜單在添加 .active 類的時候顯示,不然摺疊。這個類是經過 JavaScript 添加的,以下所示。

menuToggle.addEventListener('click', function(e){
  e.preventDefault();
  navMenu.classList.toggle('active');
});
複製代碼

menu-bad-example.gif

結果看起來不錯,但它有一個大問題。使用 opacity: 0 的方式不會將導航從訪問樹中刪除 。即使導航在視覺上隱藏了,可它仍然能被鍵盤聚焦,並且也能被屏幕閱讀器讀到。

下面是來自 Chrome DevTools 的訪問樹截圖:

下面的截圖,則是 Mac OS 上的訪問工具 VoiceOver 看到的頁面內容。跟上面同樣,

簡而言之,訪問樹是屏幕閱讀器用戶能夠訪問的全部內容的列表。在咱們的例子中,包含一個導航列表,雖然它視覺上是隱藏的,但仍是出如今了訪問樹中。所以,隱藏菜單時咱們須要解決兩個問題:

  1. 不能被鍵盤聚焦
  2. 不能被屏幕閱讀器訪問

Demo

菜單動畫 - 好的例子

爲了解決上面的文問題,咱們須要在菜單導航上使用 visibility: hidden。這確保菜單不只在視覺上是隱藏的,屏幕閱讀器也沒法訪問。

ul {
    visibility: hidden;
    opacity: 0;
    transform: translateX(100%);
    transition: 0.3s ease-out;
}

ul.active {
    visibility: visible;
    opacity: 1;
    transform: translateX(0);
}
複製代碼

添加後,如今菜單對屏幕閱讀器也是隱藏的了。讓咱們再來測試一下 VoiceOver  的結果:

Demo

自定義複選框

默認的複選框設計很難自定義。所以,咱們須要爲複選框設計自定義樣式。通常會這麼作:

<p class="c-checkbox">
  <input class="sr-only" type="checkbox" name="" id="c1">
  <label class="c-checkbox__label" for="c1">Custom checkbox</label>
</p>
複製代碼

要自定義複選框,須要以可訪問的方式隱藏輸入框。爲此,須要藉助 position 等其餘屬性來實現。有一個常見的CSS 類,稱爲 sr-onlyvisual-hidden,用來在視覺上隱藏一個元素,但鍵盤和屏幕閱讀器依然能訪問。

.sr-only {
  border: 0; 
  clip: rect(0 0 0 0); 
  -webkit-clip-path: polygon(0px 0px, 0px 0px, 0px 0px);
  clip-path: polygon(0px 0px, 0px 0px, 0px 0px);
  height: 1px; 
  margin: -1px;
  overflow: hidden;
  padding: 0;
  position: absolute;
  width: 1px;
  white-space: nowrap;
}
複製代碼

這樣,就能夠訪問自定義複選框。若是你想了解更多,我寫了關於這個主題的 一篇文章

Demo

對屏幕閱讀器隱藏內容


在標題中,我使用了一個表情符號。若是隱藏,那麼屏幕閱讀器會使用下面的方式閱讀:

Hiding On The Web grinning face with open mouth

每一個表情符號都有一個對應的特定描述,屏幕閱讀器閱讀時會使用這個描述。想象你如今正在瀏覽一個網頁,忽然聽到這個標題,讀到後面,可能就有點懵逼了。爲了不這種混淆,可使用 aria-hidden,把表情包設定爲對屏幕閱讀器隱藏。

<h1>Hiding On The Web <span aria-hidden="true">😃</span></h1>
複製代碼

小故事,大道理小改變,大勝利!

隱藏按鈕

在 Twitter 上,有一個名爲「See New Tweets」的按鈕,默認使用 aria-hidden 對屏幕閱讀器隱藏,只在有新推文可纔會顯示。

隱藏修飾性的內容

用戶 ID 和日期之間的點是裝飾性的。所以,使用了 aria-hidden="true" 避免被屏幕閱讀器讀到。

相關文章

(完)


廣告時間(長期有效)

我有一位好朋友開了一間貓舍,在此幫她宣傳一下。如今貓舍裏養的都是布偶貓。若是你也是個愛貓人士而且有須要的話,不妨掃一掃她的【閒魚】二維碼。不買也沒關係,看看也行。

瞄~

相關文章
相關標籤/搜索