Open FrankKai opened 5 years ago
这篇文章的主要解释了多种隐藏DOM元素的实现方式。
当我们谈到一个元素被隐藏(hidden)时,我们通常是理解成不可见(not visible)。 然而,显示器不是唯一的应用隐藏内容的地方。电子阅读器和盲文显示器等系统依赖于accessibility树中的文档实现。
为了消除歧义,我们将进行以下的术语约定:
完全隐藏(Completely hidden) 元素在屏幕上未渲染,在无障碍(accessibility)树中也不暴露,通过键盘获取不到访问权限。
语义上的隐藏(Semantically hidden) 元素在屏幕上渲染,在无障碍树中不暴露,通过键盘可以获取到访问权限。
视觉上的隐藏(Visually hidden) 元素在屏幕上未渲染,在无障碍树上暴露,通过键盘获取到访问权限。
通过以下表格可以很明确的对比出三种隐藏方式的异同:
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 |
完全隐藏一个元素有以下3种方式:
display: none;
visibility: hidden;
<span hidden>
以上3种方式都会有相同的效果,内容不会被渲染也不会暴露在无障碍树中,他们有不同的表现效果。
display
和visibility
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
属性是一个很方便的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;
}
为了将内容从无障碍树上隐藏,但是在屏幕上保留,我们可以使用属性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;
,因为这会导致失去仅从屏幕阅读器上隐藏元素的能力。
为了确保使无障碍树的当前结构生效,我们也许需要提供不可见的内容。下面的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来阻止空白的不希望的崩溃;。
.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;
}
仅在视觉上和语义上隐藏的元素需要注意。类似<a href="...">
的focusable element保持键盘可导航,即使元素在屏幕上不可见或者在无障碍树上不可见。
为了确保有视力的键盘用户不会最终聚焦他们看不到的元素,并且视力障碍用户没有聚焦那些不存在的元素,我们需要确保部分隐藏的内容,不能通过Tab以及Shift Tab键访问到。我们可以通过添加tabindex="-1"
给元素从而做到键盘不可导航。
原文链接:https://allyjs.io/tutorials/hiding-elements.html