飞道的博客

在网页中隐藏元素

490人阅读  评论(0)

在平时的开发工作中,有时会有隐藏元素的需求。比如,一个按钮,需要在桌面端隐藏,在手机端显示;一个导航栏,需要在手机端隐藏,在桌面端显示。“隐藏”不是字面上展示的这样简单,它还包含几层意思:

元素完全从文档流中移除的隐藏。
元素仅仅是视觉上的隐藏,使用像屏幕阅读器(screen reader)这样的辅助技术(assistive technology,简称“AT”)依然是能访问的。
元素在视觉上可见,不过对屏幕阅读器是隐藏的,即屏幕阅读器是无法访问的。

通过本篇文章,你将会学到利用 HTML/CSS 隐藏元素的方法,内容涵盖了可访问性、动画和使用案例。我们一起来看看吧!

HTML5 hidden 属性
这是在 HTML 标签上使用的一个布尔值属性。在浏览器加载页面的时候,使用 hidden 属性修饰的元素,渲染效果与 display: none 类似。当然,如果使用 CSS 手动重写了 hidden 属性的话,就另当别论了。
来看下面的例子:

这部分包含了一个标题、图片和描述信息。图片只会在视口宽度大于 400px 的时候才显示。这里我给 加了一个 hidden 属性。
我写了一段 CSS 代码,让 hidden 属性修饰的图片在视口宽度大于 400px 的时候显示。
img[hidden] {
display: none;
}

@media (min-width: 400px) {
img[hidden] {
display: block;
}
}
复制代码下面是在大视口(大于 400px)下的渲染效果。

Demo
你可能要问了,为什么不直接使用 display: none 呢?好问题。图片使用 hidden 属性控制带来的好处是——即使 CSS 由于某种原因没有加载成功,图片也会隐藏。

hidden 属性对可访问性的影响
hidden 会将元素完全从页面隐藏,所以屏幕阅读器是无法访问。如果只是出于视觉表现的目的,一定要避免使用。

CSS display 属性
每个元素都有一个默认的 display 值,可能是 inline-block、block、table 等等。我们使用 display: none 就能达到隐藏元素的效果,并且该元素的所有后代都和它一起隐藏了。
与上面代码类似,不过这次我们使用了 display: none:
img {
display: none;
}

@media (min-width: 400px) {
img {
display: block;
}
}
复制代码display: none 会将元素从文档流中移除,屏幕阅读器也是无法访问到。那么,什么是文档流?我们可以用下面的图片来生动地描述它:

我们把蓝皮书用 display: none 隐藏了,最后发现它从这摞书里完全消失了,就好像被抽走了一样。蓝皮书原来占据的空间不存在了。HTML 于此类似,说明文档流被改变了。
下面的动画,展示了蓝皮书被移除时的状况:

图片隐藏后,还会加载吗?
会的。举个例子, 默认使用 CSS 隐藏,我们将它设置在某个断点处显示。我们打开 DevTools,检查 networks 选项卡,还是发现图像被加载了,即使没有显示。

Demo

复制代码style { display: block; } 复制代码这事如果在让样式块(style block)变得可编辑,就更有趣了。可以通过为

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,那么这子元素将是可见的。

Spring is on the way

复制代码article { visibility: hidden; }

img {
visibility: visible;
}
复制代码
上例中,

使用了 visibility: hidden,而子元素 是 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);
}
复制代码
将多边形每个点的坐标设置为 (0, 0),则裁剪区域变为 0。结果,图像不会显示了。同样,还可以用一个圆(circle)来代替这里的多边形(polygon):
img {
clip-path: circle(0 at 50% 50%);
}
复制代码
使用 clip-path 实现的隐形效果只是视觉上的,屏幕阅读器依然可以访问,键盘也能聚焦。
Demo

操作 color 和 font-size
尽管这两种技术并不像我们前面讨论的那样普遍,但在某些场景下比较有用。

color: transparent
将文本设置成透明色(transparent),只是视觉上隐藏了。这比较适合仅带图标的按钮。

font-size: 0
将文字大小设置为 0 也是视觉上的隐藏。
来看一个包含如下结构的按钮:




Like

复制代码我们的目标是以一种能被访问的方式隐藏文本。为此,我使用了下面的 CSS:
.button span {
color: transparent;
font-size: 0;
}
复制代码文本隐藏了。

Demo

aria-hidden
当为元素添加 aria-hidden 后,就会从访问树中删除,这可以用来提升屏幕阅读器用户的体验。需要注意的是,元素依然是视觉可见的。

Menu


复制代码这里是一个带 label 和图表的菜单按钮。为了让 svg 对屏幕阅读器隐藏,这里添加了 aria-hidden。
根据 MDN 文档,aria-hidden 的使用场景包括:

用来隐藏修饰性内容,比如图标、图片。
隐藏重复的文字。
隐藏屏幕外的或折叠的内容。

aria-hidden 是为屏幕阅读器设计的,因此它仅对屏幕阅读器隐藏内容。但是,内容对于视觉用户仍然可见,并且也支持键盘聚焦。

动画和交互

速查表
在我们开始示例之前,我想带大家回顾一下前面提到的属性,我从 CSS-tricks 上的 这篇文章 获得了灵感,做了下面的一张速查表,方便大家在使用时根据需要选择合适的方法。

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’);
});
复制代码
结果看起来不错,但它有一个大问题。使用 opacity: 0 的方式不会将导航从访问树中删除 。即便导航在视觉上隐藏了,可它仍然能被键盘聚焦,而且也能被屏幕阅读器读到。
下面是来自 Chrome DevTools 的访问树截图:

下面的截图,则是 Mac OS 上的访问工具 VoiceOver 看到的页面内容。跟上面一样,

简而言之,访问树是屏幕阅读器用户可以访问的所有内容的列表。在我们的例子中,包含一个导航列表,虽然它视觉上是隐藏的,但还是出现在了访问树中。因此,隐藏菜单时我们需要解决两个问题:

不能被键盘聚焦
不能被屏幕阅读器访问


转载:https://blog.csdn.net/weixin_46369542/article/details/104467462
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场