原文连接:Hiding Elements On The Web,by Ahmad Shadeedjavascript
在平时的开发工做中,有时会有隐藏元素的需求。好比,一个按钮,须要在桌面端隐藏,在手机端显示;一个导航栏,须要在手机端隐藏,在桌面端显示。“隐藏”不是字面上展现的这样简单,它还包含几层意思:css
经过本篇文章,你将会学到利用 HTML/CSS 隐藏元素的方法,内容涵盖了可访问性、动画和使用案例。咱们一块儿来看看吧!html
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
会将元素彻底从页面隐藏,因此屏幕阅读器是没法访问。若是只是出于视觉表现的目的,必定要避免使用。
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 于此相似,说明文档流被改变了。
下面的动画,展现了蓝皮书被移除时的情况:
会的。举个例子,<img>
默认使用 CSS 隐藏,咱们将它设置在某个断点处显示。咱们打开 DevTools,检查 networks 选项卡,仍是发现图像被加载了,即便没有显示。
<style>
元素值得一提的是,某些元素默认就是 display: none
的。好比 <style>
。咱们能够把插入到 HTML 页面中的 <style>
的 display
值设置为 block
,这样就能看见它了。
<body>
<style> .title { color: #000; } </style>
</body>
复制代码
style {
display: block;
}
复制代码
这事若是在让样式块(style block)变得可编辑,就更有趣了。能够经过为 <style>
添加 contenteditable
属性来实现。
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
隐藏的元素上的鼠标事件。这仍是很重要的,若是一个元素看不见了,但依然能响应用户的点击、悬停或选择文本的行为,勘定是很奇怪的。
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;
}
复制代码
上例中,<article>
使用了 visibility: hidden
,而子元素 <img>
是 visibility: visible
的,结果图片依然是显示的。也就是说,子元素是能够重写父元素的 visibility
属性的。
visibility: hidden
对可访问性的影响若是一个元素 visibility: hidden
了,那么它以及它的全部后代元素都会从访问树(accessibility tree)中删除,不会被屏幕阅读器读到。
position
属性使用 position
属性将隐藏元素的原理,就是把元素移动到屏幕以外,设置其尺寸为 0 (宽和高)。好比,网页里 跳过导航(skip navigation) 连接:
为了让连接定位到屏幕以外,咱们能够这么作:
.skip-link {
position: absolute;
top: -100%;
}
复制代码
-100% 会将元素网上推出一个视口高度的距离。结果,连接就被彻底隐藏了。当连接被键盘聚焦时,则能够这样设置:
.skip-link:focus {
position: absolute;
top: 0;
}
复制代码
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
实现的隐形效果只是视觉上的,屏幕阅读器依然能够访问,键盘也能聚焦。
color
和 font-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;
}
复制代码
文本隐藏了。
aria-hidden
当为元素添加 aria-hidden
后,就会从访问树中删除,这能够用来提高屏幕阅读器用户的体验。须要注意的是,元素依然是视觉可见的。
<button>
Menu
<svg aria-hidden="true"><!-- --></svg>
</button>
复制代码
这里是一个带 label 和图表的菜单按钮。为了让 svg 对屏幕阅读器隐藏,这里添加了 aria-hidden
。
根据 MDN 文档,aria-hidden
的使用场景包括:
aria-hidden
是为屏幕阅读器设计的,所以它仅对屏幕阅读器隐藏内容。可是,内容对于视觉用户仍然可见,而且也支持键盘聚焦。
在咱们开始示例以前,我想带你们回顾一下前面提到的属性,我从 CSS-tricks 上的 这篇文章 得到了灵感,作了下面的一张速查表,方便你们在使用时根据须要选择合适的方法。
当咱们想对隐藏元素使用动画的时候。好比,显示隐藏的移动导航,须要以一种可访问的方式来实现。为了得到访问性体验,咱们将探索一些值得学习的好例子,以及一些很差的例子,避免犯错误,从而给屏幕阅读器用户带来更好的体验。
咱们有一个菜单,在展开时使用一个划入的动画。最简单的作法是使用下面的方法:
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 看到的页面内容。跟上面同样,
简而言之,访问树是屏幕阅读器用户能够访问的全部内容的列表。在咱们的例子中,包含一个导航列表,虽然它视觉上是隐藏的,但仍是出如今了访问树中。所以,隐藏菜单时咱们须要解决两个问题:
为了解决上面的文问题,咱们须要在菜单导航上使用 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 的结果:
默认的复选框设计很难自定义。所以,咱们须要为复选框设计自定义样式。通常会这么作:
<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-only
或 visual-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;
}
复制代码
这样,就能够访问自定义复选框。若是你想了解更多,我写了关于这个主题的 一篇文章。
在标题中,我使用了一个表情符号。若是隐藏,那么屏幕阅读器会使用下面的方式阅读:
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"
避免被屏幕阅读器读到。
display: none;
, but don’t(完)
广告时间(长期有效)
我有一位好朋友开了一间猫舍,在此帮她宣传一下。如今猫舍里养的都是布偶猫。若是你也是个爱猫人士而且有须要的话,不妨扫一扫她的【闲鱼】二维码。不买也没关系,看看也行。
瞄~