FrankKai / FrankKai.github.io

FE blog
https://frankkai.github.io/
363 stars 39 forks source link

[译]如何隐藏DOM元素? #142

Open FrankKai opened 5 years ago

FrankKai commented 5 years ago

原文链接:https://allyjs.io/tutorials/hiding-elements.html

FrankKai commented 5 years ago

隐藏 DOM 元素

这篇文章的主要解释了多种隐藏DOM元素的实现方式。

当我们谈到一个元素被隐藏(hidden)时,我们通常是理解成不可见(not visible)。 然而,显示器不是唯一的应用隐藏内容的地方。电子阅读器和盲文显示器等系统依赖于accessibility树中的文档实现。

为了消除歧义,我们将进行以下的术语约定:

通过以下表格可以很明确的对比出三种隐藏方式的异同:

visibility state on screen in accessibility tree keyboard navigation
completely hidden hidden hidden not navigatable
semantically hidden visible hidden navigatable
visually hidden hidden visible navigatable

无障碍树是什么?

FrankKai commented 5 years ago

如何完全隐藏元素

完全隐藏一个元素有以下3种方式:

以上3种方式都会有相同的效果,内容不会被渲染也不会暴露在无障碍树中,他们有不同的表现效果。

CSS属性displayvisibility

display:none;会导致元素完全消失,它不会占用任何空间,也不是animatable的。 visibility:hidden;允许动画并且保留元素在屏幕上的占用空间,会留一个blank(一个空白区域)。可以通过visibility:visible去显示嵌套的内容:

<div style="visibility: hidden">
  <span>not visible</span>
  <span style="visibility: visible">visible!</span>
</div>

提醒:尽量不要用visibility: visible;去显示一个嵌套的子元素,会导致父元素设置hidden失效。

HTML5的hidden属性

HTML5的hidden属性是一个很方便的API,可以很方便的通过element.hidden=true;控制元素的显示或控制。元素自己不会隐藏内容,但是浏览器内部的样式表会包含以下的CSS规则:

[hidden] {
    display: none;
}

安全地重写hidden属性

我们千万不要恢复hidden属性的隐藏效果。然而,可以交换display以查看visibility,例如我们可以通过以下方式使得元素可动画:

.my-element[hidden] {
  display: block;
  visibility: hidden;
}

但是我们不能用inherit,initial或者unset去撤销display:none;initial和unset将会转换成display:inline,inherit会继承父元素的属性。我们可以使用扩展选择器去解决重复定义的问题:

.my-element,
.my-element[hidden] {
  display: block;
  /* ... */
}
.my-element[hidden] {
  visibility: hidden;
}
FrankKai commented 5 years ago

如何语义上隐藏元素

为了将内容从无障碍树上隐藏,但是在屏幕上保留,我们可以使用属性aria-hidden="true"

例如,我们可能希望隐藏某些用于非描述性,纯粹美学目的的图像和图标:

<a href="https://google.com">
  <img src="search-symbol.png" alt="" aria-hidden="true">
  Google Search
</a>

提示:不能给CSS选择器[aria-hidden="true"]增加任何可视的样式visibility:hidden;``display:none;,因为这会导致失去仅从屏幕阅读器上隐藏元素的能力。

FrankKai commented 5 years ago

如何从视觉层面隐藏元素

为了确保使无障碍树的当前结构生效,我们也许需要提供不可见的内容。下面的CSS来自HTML-bp,这是基于无障碍隐藏元素的。

.visuallyhidden {
  position: absolute;

  width: 1px;
  height: 1px;
  margin: -1px;
  border: 0;
  padding: 0;

  clip: rect(0 0 0 0);
  overflow: hidden;
}

CSS属性clip在任何浏览器都是被支持的,但是在CSS Masking 1中被弃用。取而代之的,我们建议使用clip-path,它还没有被广泛支持。所以会用clip-path:inset(100%)去覆盖clip:rect(0 0 0 0)样式。

当Internet Explorer 9 - 11使溢出的容器focusable,clip确保绘制的outline,:focus不可见,并且无法单击该元素。

说到可聚焦元素,我们可能会使用.visuallyhidden样式进行跳过链接,在这种情况下,我们需要一种方法来撤消视觉隐藏。 HTML5 Boilerplate为此提供了以下样式:

.visuallyhidden.focusable:active,
.visuallyhidden.focusable:focus {
  position: static;

  width: auto;
  height: auto;
  margin: 0;

  clip: auto;
  overflow: visible;
}

但是,这种方法会带来一些问题。首先,我们需要通过添加可聚类类来声明元素兼容。第二,更重要的是 ,我们将样式重置为可能不是我们想要渲染的值。相反,我们可以使用:not(),这在每个现代浏览器中都受支持。 根据Beware推出的屏幕外可访问文本,上面的CSS片段可能会给某些屏幕阅读器带来问题。似乎(在某些情况下)单独的单词可能会被连接起来,因此很奇怪。幸运的是,我们可以通过添加white-space: nowrap来阻止空白的不希望的崩溃;。

2017版的.visuallyhidden

.visuallyhidden:not(:focus):not(:active) {
  position: absolute;

  width: 1px;
  height: 1px;
  margin: -1px;
  border: 0;
  padding: 0;

  white-space: nowrap;

  clip-path: inset(100%);
  clip: rect(0 0 0 0);
  overflow: hidden;
}
FrankKai commented 5 years ago

Keyboard navigation

仅在视觉上和语义上隐藏的元素需要注意。类似<a href="...">的focusable element保持键盘可导航,即使元素在屏幕上不可见或者在无障碍树上不可见。

为了确保有视力的键盘用户不会最终聚焦他们看不到的元素,并且视力障碍用户没有聚焦那些不存在的元素,我们需要确保部分隐藏的内容,不能通过Tab以及Shift Tab键访问到。我们可以通过添加tabindex="-1"给元素从而做到键盘不可导航。

FrankKai commented 5 years ago

总结