您可能认为使用 CSS 隐藏内容是一个简单且已解决的问题,但实际上有多种解决方案,每种解决方案都独一无二。
开发人员 最常使用 display: none
来隐藏页面上的内容。不幸的是,这种隐藏内容的方式并非万无一失,因为现在该内容对屏幕阅读器 “不可访问”。虽然使用它很诱人,但尤其是在只有视觉上隐藏内容的情况下,不要使用它。
事实上,CSS 中有许多方法可以“隐藏”内容,每种方法都有其优缺点,这些优缺点在很大程度上取决于它的使用方式。我们将在这里回顾每种技术,并在最后总结一下,帮助我们决定何时使用哪种技术。
如何区分这些技术之间的差异
为了看到不同隐藏内容方式之间的差异,我们必须引入一些指标。我们将使用这些指标来比较这些方法。我决定通过提出一些问题来分解这些指标,这些问题侧重于影响布局、性能和无障碍性的四个特定领域。
- 无障碍性:屏幕阅读器是否可以读取隐藏的内容?
- 文档流:隐藏元素是否会影响文档布局?
- 渲染:隐藏元素的盒子模型是否会被渲染?
- 事件触发器:元素是否检测点击或焦点?
现在我们已经确定了标准,让我们来比较这些方法。同样,我们将把所有内容放在最后汇总起来,我们可以用它作为参考,在隐藏 CSS 内容时做出决策。
display
属性
方法 1:我们在文章开头就警告过不要使用 display
来隐藏内容。正如我们所建立的,使用它来隐藏元素意味着该元素根本不会生成。它存在于 DOM 中,但实际上从未渲染过。
如果检查页面,该元素将继续显示在标记中。盒子模型不会生成或出现在页面上,这也适用于**所有子元素**。
更重要的是,如果该元素有任何事件监听器(例如点击或悬停),它们根本不会注册。正如我们已经讨论过的,所有内容都会被屏幕阅读器忽略。在这里,我们有两个可见按钮和一个使用 display: none
隐藏的按钮。所有三个按钮都有点击事件,但只有两个可见按钮会渲染并注册点击事件。
Display 是唯一影响图像请求触发的属性。如果一个图像标签(或父元素)的 display
属性设置为 none
(通过内联 CSS 或选择器),那么图像将被下载。另一方面,如果图像使用 background
属性应用,那么图像将不会被下载。
这是因为解析器在解析 HTML 文档时还没有应用 CSS,并且它遇到了一个 <img>
标签。另一方面,当我们使用 background
属性将图像应用于元素时,图像将不会被下载,因为解析器还没有应用调用图像的 CSS。这种行为在所有最新浏览器中都是一致的。唯一的例外是 IE 11,它将在两种情况下都下载图像。
指标 | 结果 |
---|---|
屏幕阅读器是否可以读取隐藏的内容? | ❌ |
隐藏元素是否会影响文档布局? | ❌ |
隐藏元素的盒子模型是否会被渲染? | ❌ |
元素是否检测点击或焦点? | ❌ |
visibility
属性
方法 2:如果元素的 visibility
属性设置为 hidden
,那么该元素将被“视觉上隐藏”。“视觉上隐藏”听起来很像 display: none
的作用,但它与之大不相同,因为该元素会被生成和渲染,只是不可见。这意味着元素的盒子模型存在,它会占用屏幕上的空间,即使它看起来并不在那里。
想象一下你穿着一件隐形斗篷,使你对其他人不可见,但你仍然可以撞到东西。你的身体存在,即使你对人眼不可见。
但这就是“视觉上隐藏”和“不显示”之间差异的终点。事实上,使用 visibility
和 display
隐藏的元素在无障碍性和事件触发器方面表现相同。不可见的元素对屏幕阅读器不可访问,并且不会注册事件,正如我们在下面的演示中看到的那样,它与上一个示例完全相同,只是将 display: none
换成了 visibility: hidden
。
指标 | 结果 |
---|---|
屏幕阅读器是否可以读取隐藏的内容? | ❌ |
隐藏元素是否会影响文档布局? | ✅ |
隐藏元素的盒子模型是否会被渲染? | ✅ |
元素是否检测点击或焦点? | ❌ |
opacity
属性
方法 3:opacity
属性只影响元素的视觉效果。如果我们将元素的 opacity
设置为零,则该元素将完全透明。同样,这非常类似于 visibility: hidden
,我们将一件隐形斗篷披在元素上,使它不可见,但仍然存在。
换句话说,我们得到的是一个空心的透明元素,它像任何其他元素一样工作,只是它不可见。听起来很像 visibility
方法,对吧?区别在于完全透明的元素仍然可以被屏幕阅读器访问,并且可以注册事件,例如点击事件,正如我们在下面的示例中看到的。
指标 | 结果 |
---|---|
屏幕阅读器是否可以读取隐藏的内容? | ✅ |
隐藏元素是否会影响文档布局? | ✅ |
隐藏元素的盒子模型是否会被渲染? | ✅ |
元素是否检测点击或焦点? | ✅ |
position
属性
方法 4:使用绝对定位将元素推离屏幕是开发人员经常用来隐藏内容的另一种方法。使用 top
和 left
,我们可以将元素推到屏幕外,这样它就永远不会被看到。这就像把饼干罐藏在房子外面,这样孩子们(或者也许是你!)就找不到它们。
“绝对”是这里关键词。如果我们将 position
设置为 absolute
,则元素将从文档流中移除,这意味着它不再遵守其在 DOM 中的自然位置。换句话说,页面不会为它保留任何空间,这会使元素在视觉上失去顺序,如果存在,则将其定位到最近的定位元素,如果不存在,则定位到文档根元素。
我们利用绝对定位将“隐藏”元素从文档流中移除,并使用 -9999px
的值将其偏移到左上角。
.hidden {
position: absolute;
top: -9999px;
left: -9999px;
}
指标 | 效果 |
---|---|
屏幕阅读器是否可以读取隐藏的内容? | ✅ |
隐藏元素是否会影响文档布局? | ❌ |
隐藏元素的盒子模型是否会被渲染? | ✅ |
元素是否检测点击或焦点? | ✅ |
如果隐藏的元素包含可聚焦内容,则页面会在该元素处于焦点时滚动到该元素,导致页面突然跳动。
方法 5:“视觉上隐藏”类
到目前为止,position
方法是我们在 CSS 中看到的最接近无障碍隐藏的方式。但可聚焦内容导致页面突然跳动的问题并不理想。另一种无障碍隐藏方法是结合绝对定位、clip
属性和隐藏溢出。Scott O’Hara 于 2017 年 在博客中介绍了它。
.visually-hidden:not(:focus):not(:active) {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
让我们分解一下。
我们需要将元素从文档流中移除。最好的方法是使用 position: absolute
。这将移除元素,但我们不会将其推离屏幕。
.visually-hidden {
position: absolute;
}
我们可以通过将宽度和高度属性设置为零来隐藏元素。不幸的是,这行不通,因为一些屏幕阅读器会忽略宽度和高度为零的元素。我们可以做的是将其设置为第二低的值,1px
。这意味着内容很容易溢出空间,因此我们还需要 overflow: hidden
来确保它不会在视觉上溢出。
.visually-hidden {
height: 1px;
overflow: hidden;
position: absolute;
width: 1px;
}
为了隐藏那个 1 像素的正方形,我们可以使用 CSS 的 裁剪属性。它非常适合这种情况,因为它不会影响屏幕阅读器。内容存在,但仍然是视觉上隐藏的。需要注意的是,clip
已被弃用,取而代之的是 clip-path
,但如果我们需要支持旧版本的 Internet Explorer,它仍然是必需的。
.visually-hidden {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
width: 1px;
}
“视觉隐藏”类谜题的另一个部分是解决挤压在屏幕外可访问文本,这是一种奇怪现象,它会删除单词之间的空格,导致它们被朗读成一个大字符串。例如,“欢迎回家”将被读作“Welcomebackhome”。
解决此问题的一个简单方法是设置white-space: nowrap
.visually-hidden {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
最后!要考虑的最后一件事是允许某些具有本机焦点和活动站点的元素在它们获得焦点时显示,同时继续阻止其他元素(如段落)显示。我们可以使用:not
伪选择器来实现。
.visually-hidden:not(:focus):not(:active) {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
指标 | 结果 |
---|---|
屏幕阅读器是否可以读取隐藏的内容? | ✅ |
隐藏元素是否会影响文档布局? | ❌ |
隐藏元素的盒子模型是否会被渲染? | ❌ |
元素是否检测点击或焦点? | ✅ |
值得一提的是
除了我们介绍的五种方法之外,还有更多的方法。例如,text-indent
属性可以像position
方法一样将文本推离屏幕
.hidden {
text-indent: -9999em;
}
不幸的是,这种方法与RTL写作模式不兼容。这使得它不如我们介绍的其他解决方案灵活。
另一种方法是使用transform
来缩放或移动元素以使其离开屏幕。它与opacity
的功能相同——只是视觉上的——。
.hidden {
transform: scale(0);
}
让我们将所有内容整合在一起!
我们找到了一个可以视觉隐藏内容,但仍然可访问的解决方案。那么,你应该停止使用display: none
吗?不,这仍然是完全隐藏元素(视觉上和可访问地)的最佳方法。
也就是说,值得一提的是,如果你想要实现相反的结果——从屏幕阅读器中隐藏内容,aria-hidden="true"
属性将从屏幕阅读器中隐藏内容,但不会在视觉上隐藏。
因此,这里有一个完整的表格,比较了所有方法。当你下次遇到这种情况时,可以使用它来指导你如何隐藏内容的决定。
指标 | 显示 | 可见性 | 不透明度 | 位置 | 可访问的方式 |
---|---|---|---|---|---|
屏幕阅读器是否可以读取隐藏的内容? | ❌ | ❌ | ✅ | ✅ | ✅ |
隐藏元素是否会影响文档布局? | ❌ | ✅ | ✅ | ❌ | ❌ |
隐藏元素的盒子模型是否会被渲染? | ❌ | ✅ | ✅ | ✅ | ❌ |
元素是否检测点击或焦点? | ❌ | ❌ | ✅ | ✅ | ✅ |
位置和低于0的z-index可以是另一种隐藏网页元素的方法。
那是真的。但z-index有很多注意事项,这就是人们避免它的原因。例如,添加
transform
或opacity
会将元素放入它自己的新堆叠上下文或者网格和z-index。
同样的技巧可以用于https://css-tricks.org.cn/how-to-create-a-skip-to-content-link/
我不明白
display:none
方法的无障碍问题。它说:“隐藏内容不会被屏幕阅读器读取”。
好吧。
难道这不是目的吗?
是的,但在所有情况下并非如此。这有点是我们在这里要说的:有很多不同的方法,每种方法都可能在某些情况下更有效。
我们通常会得出这个结论。因为我们有完美的视力,可以看到该项目周围的上下文。另一方面,失明或存在其他无障碍问题的用户将不会意识到这一点。
一个很好的例子是输入标签。我们通常会在响应式设计中隐藏它们,或者根本不包含它们,而这是错误的。我们应该只在视觉上隐藏它们,但仍然让它们可供屏幕阅读器访问。
这篇文章探讨了隐藏内容的不同方法以及这些操作的结果。
99% 的情况
经理 1:我需要一个按钮
经理 2:功能还没有准备好,隐藏它,不要破坏布局
屏幕阅读器:H-E-L-L-O,按钮。点击我。点击我。点击我。
喜欢这个……不幸的是,这是真的……
非常有趣的文章!
你也可以通过将元素的高度和宽度设置为0px来隐藏它,有时还需要将填充或边距设置为0px。
注意,(大多数)屏幕阅读器不会读取宽度和高度为0的元素。
隐藏或
display:none
在响应式行为中被广泛使用。但这对移动用户在页面下载速度方面没有帮助,因为元素仍然被下载(例如:图像)。有没有办法完全隐藏元素?比如使用JavaScript的.remove,这样浏览器可以更快地为移动用户加载内容?正如文章中所述,如果你有
background-image
,它不会被下载。另一方面,img
会被下载。你所要求的有点不可能实现,因为你需要反向操作。
为了让图像不被下载,它们需要被HTML解析器跳过。这意味着你需要在解析器遍历它们之前移除它们。这是不可能的,因为你需要在JS中选择那个元素并移除它,对吧?但是你无法选择解析器没有附加到DOM树的东西。
在
<head>
中添加一个<script>
不起作用,因为正如上面所述,文档尚未被解析。在<body>
的底部添加它为时已晚,因为它已经被解析,图像请求已经被发送。要实现这一点,你需要反过来思考,添加元素而不是移除它们。你可以做的是在页面加载时使用JavaScript媒体查询检查分辨率,并在需要时添加元素。
我找到的最接近你所要求的操作的是使用picture元素,并使用srcset和base64图像来表示最小的尺寸。查看此链接以了解更多详情。我希望它能有所帮助!
https://sjardo.com/disable-loading-images-on-mobile/
那么HTML属性hidden的作用是什么?!
文章标题是“比较在CSS中隐藏事物的各种方法”,但没错,HTML属性
hidden
会自动将display: none
应用于支持它的浏览器的元素。对于不支持hidden
属性的浏览器,可以使用像这个网站这样的CSS:[hidden] { display: none }
。为什么
clip: rect(0 0 0 0);
可以隐藏内容?我以为用零偏移量的剪裁矩形不会剪裁任何东西。我在codepen中尝试了这个,似乎clip
会隐藏它应用的元素,无论剪裁偏移量是什么,也不管框的尺寸、填充或边框是什么,这对我来说毫无意义。我想这是它被弃用的一件好事。如果你要隐藏的只是文本,就像这样
<div class="logo">
<svg>...</svg>
<a href="/">主页</a>
</div>
我经常使用
.logo {position:relative;}
.logo a {position:absolute !important; left:0; right:0; top:0; bottom:0; font-size:0}
所有内容仍然可以被 Tab 键选中,并且处于正常流中,只是文本大小太小而无法看到。有人能想到在当前的现代浏览器中使用这种方法的任何问题吗?
如果你有一个JavaScript MIDI 音序器,启动它,然后切换到轨道控制(
…控制…
) ?
使用
display: Block
会导致计时器掉帧 :(或者,是否最好使用画布元素创建和切换部分控制(部分步骤需要每个步骤的复选框来播放样本(复选框的读取性能如何?所有部分的所有复选框都必须可读))?
有人有什么想法吗?
非常感谢!