Web隐藏术
在Web页面或Web应用程序的开发中,有些元素是需要被隐藏起来。让一个元素隐藏起来的实现方案会有很多种,比如说在《图片替换文本CSS方法》一文中所聊的图片替代文本的方案都适合于元素的隐藏,只不过每种不同的技术方案实现的原理和最终呈现给用户的渲染方式会有所不同。如果你是一个有情怀的前端开发者的话,在开发应用的时候很多时候还会考虑无障碍(可访问性)设计相关的细节。那么隐藏元素的不同技术手段对读屏软件之类的也是有所不同的。在这篇文章中,我们就一起来聊聊Web中隐藏术。
能想到的Web隐藏术
如果你阅读了《图片替换文本CSS方法》一文的话,你至少想到了十多种隐藏Web元素的姿势:
- 设置
display
的值为none
,这种方法也被称为**FIR方法** - 负
margin
值(一个足够大让元素移出视窗外的负margin
值) - 负
text-indent
值(text-indent
具有一个足够大的负值时,可以达到隐藏文本的效果) - 设置
height
、font-size
和line-height
值为0
,让元素在视觉上不可见 - CSS的
clip
让元素在视觉上不可见 position:absolute
配合任何一个足够大的left
、right
、bottom
或top
的负值,让元素不在视窗范围内显示visibility
设置值为hidden
在视觉上让元素不可见opacity
设置值为0
在视觉上让元素不可见clip-path
让元素在视觉上不可见- HTML元素添加
hidden
属性,让元素不可见 filter
的opacity()
取值为0
在视觉上让元素不可见mix-blend-mode
在高亮模式下,让视觉上元素不可见
你应该还能想到有类似的其他方式,让一个Web元素真的或假的(视觉上)隐藏起来。
Web隐藏术的差异
上述提到的那些技术手段都可以让Web元素真或假隐藏。但它们在Web中的具体渲染还是有所差异性的,如果您想彻底的掌握应该在什么样的场景之下采用哪种隐藏术,那么就有必要先掌握这些Web隐藏术在具体的渲染中的差异性。而要了解他们之间的差异性,我们可以围绕着下面这五个方面来展开或探讨:
- 是否生成盒模型?
- 该盒模型是否影响布局?
- 该盒子在屏幕上可见吗(视觉上可见)?
- 元素的内容会被屏幕阅读器读取吗?
- 元素是否可操作(可单击,可聚焦)吗?
如此一来,接下来我们就来围绕着这五个方面来深入的了解Web隐藏术。
display
在CSS的世界中,HTML中的任何一个元素都是一个矩形框,即 盒模型。可以通过display
的值来改变盒模型在Web页面中的渲染模式。使用display
设置为none
值时可以隐藏元素,不会产生这个盒模型。
尽管元素仍然在HTML标记中(如果使用浏览器开发者工具查看到元素),但实际上它并不存在于页面中。盒模型的任何部分(内容区域、填充区域、边框区域或外距区域)都不会生成或出现在页面上。
设置了display: none
的元素以及其后代元素中的任何内容在功能上都不存在。如果它是一个可操作的元素,例如button
或a
,则不能对其进行操作。元素和其中的任何内容也会被屏幕阅读器忽略。
围绕着前面提到的五个点,填个表格:
隐藏术 | 是否有盒模型 | 是否影响布局 | 屏幕上是否可见 | 屏幕阅读器是否可读 | 元素是否可操作 |
---|---|---|---|---|---|
display: none |
✗ | ✗ | ✗ | ✗ | ✗ |
hidden属性
HTML5的hidden
属性提供了一个语义指示器:
所有HTML元素都可能有
hidden
内容属性集。hidden
属性是一个布尔属性。当在元素上指定时,它表示该元素还不相关或者不再相关。用户代理不应该渲染具有指定hidden
属性的元素。
简单地说,在HTML元素上,我们可以显式的设置hidden
属性,如果元素上具备hidden
属性,它就不会被显示。
规范中定义的后一部分很有趣,因为这表明你可以使用hidden
属性将内容放在页面中,然后通过JavaScript访问该内容,以便在其他地方使用。例如,在使用了hidden
的<textarea>
元素。另外,在使用hidden
属性时,有一些事情我们是需要有所了解的,正如规范中所描述的:
- 不应该使用
hidden
来隐藏应该可以在不同大小的屏幕、分辨率等上访问的内容 - 不应该使用
hidden
来隐藏选项卡组件(Tab)的不可见部分或类似的内容切换器 - 非隐藏元素不应该超链接到
hidden
元素上 - 标记为
hidden
的元素仍然可能是活动的。例如,表单控件甚至<script>
元素仍然是功能性的
事实上,HTML5的hidden
属性带来的效果:
- 在支持的浏览器中,内容不可见(用户看不到,不会在屏幕上显示)
- HTML代码状态语义指示器
- 客户端代理样式:
display: none
- 使用
tab
无法获取到焦点 - 不会被包括在可访问性树中
在使用hidden
属性时,在易访问性上有相应的映射属性。它被映射到aira-hidden="true"
,但它的行为与aria-hidden="true"
不同。@Steve Faulkner在他的博客中做过相关的解释,详细解释了许多的不同之处。当然,最值得注意的是,具有aira-hidden="true"
的元素在浏览器中仍然可见,但对于辅助技术则不可见(比如屏幕阅读器就会忽略),而且hidden
的元素在任何地方都无法访问。
在@Steve Faulkner的文章中还解释了如何正确的使用hidden
属性:如果你想对所有用户隐藏内容,请使用HTML5的hidden
属性。没有必要使用aria-hidden
属性。
有关于
aria
方面更详细的介绍,可以阅读《WAI-ARIA 无障碍Web规范》一文。
接下来,回到我们的主题中来,设置了hidden
属性的元素正如前面所描述的一样,元素不可见。如果你使用浏览器开发者工具查看代码的话,会发现对应的display
值为none
:
当hidden
的值在true
和false
之间切换时,元素在屏幕上隐藏和显示之间会进行切换。
仔细对比,它和display:none
的表现是相似的:
隐藏术 | 是否有盒模型 | 是否影响布局 | 屏幕上是否可见 | 屏幕阅读器是否可读 | 元素是否可操作 |
---|---|---|---|---|---|
hidden="true" |
✗ | ✗ | ✗ | ✗ | ✗ |
hidden="false" |
✓ | ✓ | ✓ | ✓ | ✓ |
同样的,显式设置了hidden
的元素,可以显式的设置display
为非none
的值,即可让元素可见。
visibility: hidden
在CSS中,如果显式的给元素设置了visibility
属性的值为hidden
的话,那么该元素或其后代元素将会不可见(不会在屏幕上可视)。但它和display:none
或hidden
有所不同,仍然会生成盒模型。由于生成了盒模型,所以构成盒模型的四个区域将会影响页面其余部分的布局。然而这四个区域在屏幕上是不可见的。
使用visibility:hidden
的元素除了生成了盒模型之外,其他的特性和display:none
类似。我们不能对该元素进行操作,屏幕阅读器也会忽略该元素。
如果使用浏览器开发者工具查阅设置了visibility:hidden
的元素,不难发现,元素虽然不可见,但其在布局中还是占有相应的区域(盒模型区域依旧在屏幕上):
隐藏术 | 是否有盒模型 | 是否影响布局 | 屏幕上是否可见 | 屏幕阅读器是否可读 | 元素是否可操作 |
---|---|---|---|---|---|
visibility:hidden |
✓ | ✓ | ✗ | ✗ | ✗ |
opacity: 0
opacity
在CSS中主要是用来设置元素的透明度的。其值是0~1
之间的一个值(小于0
会以0
渲染,大于1
会以1
渲染),该值越趋近于0
时,元素在视觉上就越不可见。
当元素的opacity
的值设置为0
,元素在屏幕上不可见(屏幕上隐藏起来),但在功能上与将元素设置为任何纯色没有什么不同。元素仍然像往常一样占用布局的空间,屏幕阅读器同样能读取到,而且同样具有交互可操作性。
隐藏术 | 是否有盒模型 | 是否影响布局 | 屏幕上是否可见 | 屏幕阅读器是否可读 | 元素是否可操作 |
---|---|---|---|---|---|
opacity:0 |
✓ | ✓ | ✗ | ✓ | ✓ |
在filter
属性中的opacity()
函数和opacity
类似,通过该函数也可以控制元素的透明度,从而让元素在屏幕上是否可见。
如果使用opacity:0
来隐藏元素,在屏幕阅读器和pointer-events
的使用上会存在一定的缺陷。@Zell Liew在他的博文《A new (and easy) way to hide content accessibly》围绕着这方面有过深入的讨论。
position
position
属性通常不用来隐藏元素。但在某些情景之下,需要在页面上可视化的隐藏一个元素,并且不影响页面布局时,使用position
(一般取值absolute
)属性配合top
和left
的值(一个较大的值,可以是正值,也可以是负值)达到元素可视化隐藏。
简单地说,position
值为absolute
结合left
、top
等值可以将某个元素脱离文档流(让该元素不在视窗可视区域)。从而达到视觉上的不可见。另外,使用该方法来隐藏某个元素时,一般在该元素的祖先容器上设置overflow:hidden
。
隐藏术 | 是否有盒模型 | 是否影响布局 | 屏幕上是否可见 | 屏幕阅读器是否可读 | 元素是否可操作 |
---|---|---|---|---|---|
position:absolute |
✓ | ✗ | ✗ | ✓ | ✓ |
在实际开发中,有的同学会使用margin
的负值(足够大的一个负值)将元素移出屏幕可视区域,从而达到元素不可见。和position:absolute
不同的是,设置负margin
的元素在布局中还是会占用布局空间,从视觉上看上去有点类似于opacity: 0
、visibility:hidden
的效果。
clip 和 clip-path
首先声明,
clip
已经从Web标准中已移除,使用clip-path
来替代,但有些为了兼容较低版本IE浏览器时,还是会使用clip
属性,另外,在使用clip
属性的元素一定是要一个显式设置position
为非static
(和relative
)。更详细的可以阅读《Clip》一文。
在A11y提供的一个经典的隐藏元素的方案使用的就是clip
和clip-path
结合在一起:
.sr-only {
position: absolute;
height: 1px;
width: 1px;
clip: rect(1px 1px 1px 1px);
clip: rect(1px,1px,1px,1px);
clip-path: polygon(0px 0px, 0px 0px, 0px 0px);
-webkit-clip-path: polygon(0px 0px, 0px 0px, 0px 0px);
overflow: hidden !important;
}
如果忽略clip
的使用,那么未显式的设置position:absolute
时。或者说,仅设置clip-path
属性,该元素也是不可见:
仅视觉上的效果来看,和visibility:hidden
、opacity:0
并无太大的差异化。
隐藏术 | 是否有盒模型 | 是否影响布局 | 屏幕上是否可见 | 屏幕阅读器是否可读 | 元素是否可操作 |
---|---|---|---|---|---|
clip-path |
✓ | ✓ | ✗ | ✓ | ✗ |
如果你从未接触过
clip-path
,而且你又对这方面感兴趣,可以点击这里进行了解。
mask
既然clip-path
可以让元素不可见,那么CSS Masking Module Level1中的另一部分Masking中的相关特性应该也可以达到在视觉上隐藏元素的效果。
简单地说,CSS的mask
也可以让某元素在视觉上不可见。
有关于CSS的
mask
在这里不做过多表述,感兴趣的可以阅读前几篇教程:《探索CSS Masking模块:Clipping》、《探索CSS Masking模块:Masking》和《Clipping和Masking 何时使用》。
如果你阅读了前面的系列教程的话,就知道mask
用来遮盖元素(即让元素可见或不可见)有两种模式:高亮模式 和 Alpha通道模式:
这样一来,只需要在隐藏的元素上添加mask-image
属性,设置一个全透明的背景图片,就可以让元素在视觉上不可见:
.is-mask {
mask: linear-gradient(to right, rgba(0,0,0,0), rgba(0,0,0,0));
}
能达到类似clip-path
、visibility:hidden
和opacity:0
的效果:
隐藏术 | 是否有盒模型 | 是否影响布局 | 屏幕上是否可见 | 屏幕阅读器是否可读 | 元素是否可操作 |
---|---|---|---|---|---|
mask |
✓ | ✓ | ✗ | ✓ | ✓ |
改变视觉尺寸
前面也提到了,HTML中任何一个元素都是一个矩形盒子,CSS中盒模型相关的属性用来描述该盒子所有。如果我们显式的将盒子尺寸都设置为0
的时候,在视觉上,该元素就会不可见。
另外,max-height
也能达到类似的效果。将max-height
设置为0
可以让元素视觉上不可见。而且很多场景会借助max-height
从0
至一个显式的值,比如1000px
,让该元素有一个展开的动效。当然之种动效不是最佳的效果,但在隐藏元素的效果上还是不错的。
隐藏术 | 是否有盒模型 | 是否影响布局 | 屏幕上是否可见 | 屏幕阅读器是否可读 | 元素是否可操作 |
---|---|---|---|---|---|
改变盒型尺寸 | ✓ | ✓ | ✗ | ✓ | ✓ |
transform
前面提到过margin
可以将元素移出视窗可视区域,从而达到元素不可见的效果。CSS中的transform
的translate()
也可以达到类似的效果。除此之外,还可以通过scale()
函数达到类似的效果,将该函数的值设置为0
,即缩小至不可见。从而达到元素不可见的效果。
隐藏术 | 是否有盒模型 | 是否影响布局 | 屏幕上是否可见 | 屏幕阅读器是否可读 | 元素是否可操作 |
---|---|---|---|---|---|
transform |
✓ | ✓ | ✗ | ✓ | ✓ |
简单地小结一下
前面简单的介绍了九种不同的方式来隐藏Web上的元素,而且围绕着五个不同方面来展开,将这些方式整合成一个更详细的表格,大家在实际使用的时候可以有一个更好的参考:
隐藏术 | 是否有盒模型 | 是否影响布局 | 屏幕上是否可见 | 屏幕阅读器是否可读 | 元素是否可操作 |
---|---|---|---|---|---|
display: none |
✗ | ✗ | ✗ | ✗ | ✗ |
hidden="true" |
✗ | ✗ | ✗ | ✗ | ✗ |
visibility:hidden |
✓ | ✓ | ✗ | ✗ | ✗ |
opacity:0 |
✓ | ✓ | ✗ | ✓ | ✓ |
position:absolute |
✓ | ✗ | ✗ | ✓ | ✓ |
clip-path |
✓ | ✓ | ✗ | ✓ | ✗ |
mask |
✓ | ✓ | ✗ | ✓ | ✓ |
改变盒型尺寸 | ✓ | ✓ | ✗ | ✓ | ✓ |
transform |
✓ | ✓ | ✗ | ✓ | ✓ |
而且下面几种方式:
opacity: 0
visibility:hidden
clip-path
mask
- 改变视觉尺寸
transform
从视觉效果上可以让元素不可见,但元素还是会占据布局的空间。如果真正的想让元素不可见,而且不占用任何布局空间,那么在这几种方式中添加position: absolute
。这样一来就可以让元素脱离文档流,从而不影响页面的布局。
Web隐藏元素的使用场景
可以说,上面聊的都是一些理论方面的东西,如何使用HTML5或CSS的特性来让元素不可见(隐藏)。那么在实际中,什么场景下来使用Web隐藏术呢?
图像替换文本
在Web使用中,常常会碰到图片替换文本的场景,比如说网站的Logo、Web图标等。而大部分同学可能会直接在一个空标签上使用background-image
,比如:
<h1 class="logo"></h1>
.logo {
background: url(logo.png)
}
从视觉效果上来看,并没有什么差异。你还原了所需要的UI效果。但如果在可访问性(无障碍设计)上深究的话,上述的方案并不是一个较好的方案。就拿屏幕阅读器来说,并读不到上面的内容。如果我们把上面提到的元素隐藏的技术运用到这里,那么效果会变得更好:
<h1 class="logo">
<span class="sr-only">W3cplus!记述前端那些事,引领Web前沿,打造精品教程!</span>
</h1>
.logo {
background: url(logo.png)
}
.sr-only {
// 前面提到的任何一种可隐藏元素的方式都可行
}
好此一来,不仅还原了UI效果,还能在可访问性上更佳(屏幕阅读器可以读到.sr-only
中的内容)。
目前,sr-only
常用的方式是clip-path
:
.sr-only {
position: absolute;
height: 1px;
width: 1px;
clip: rect(1px 1px 1px 1px);
clip: rect(1px,1px,1px,1px);
clip-path: polygon(0px 0px, 0px 0px, 0px 0px);
overflow: hidden !important;
}
如果想让元素获得焦点时,隐藏的元素显示式出来,比如说使用Tab
键,定位到隐藏的元素显示出来。我们需要对上述的选择器做一个小小调整:
.sr-only:not(:focus):not(:active) {
position: absolute;
height: 1px;
width: 1px;
clip: rect(1px 1px 1px 1px);
clip: rect(1px,1px,1px,1px);
clip-path: polygon(0px 0px, 0px 0px, 0px 0px);
overflow: hidden !important;
}
要是没使用sr-only
来隐藏元素,而是采用aira-hidden="true"
来隐藏元素的话,可以考虑@Nicolas Hoffmann提供的方案。
转场动画
前段时间@张鑫旭老师的《你用的那些CSS转场动画可以换一换了》一文中重新介绍了一些实现转场动效的技术方案。事实上,我们可以把隐藏元素的一些技巧运用进来,也可以让转场动效变得更为有意思。正如@张鑫旭 老师教程中提到的clip-path
、mask
相关特性,你会发现,这两个特性也可以被运用于隐藏元素中。
除了教程中提到的案例,类似的转场效果还很多,比如这里提供的一些案例效果:
总结
这篇文章主要和大家一起探讨了Web中的隐藏术。虽然隐藏元素的方式有很多种,但总结起来就是三大类:
- 完全隐藏
- 视觉上隐藏
- 只是在辅助技术上隐藏
虽然这些方式都可以达到元素隐藏(或显式)之间的切换,但每种方式都有自己的利弊,在实际使用的时候还是需要根据运用场景来选择:
- 使用CSS或
[hidden]
完全隐藏内容 - 使用像
.sr-only
可视化隐藏内容,但对辅助技术可用(不隐藏) - 使用
aria-hidden="true"
让屏幕阅读器忽略内容