深入研究显示属性:框生成
已发表: 2022-03-10display
属性系列,这次 Rachel Andrew 看看控制框生成的值,对于那些你根本不想生成框的时候。 这是关于 CSS 中display
属性的短系列文章中的第二篇。 您可以在“展示的两个价值”中阅读该系列的第一篇文章。 display
规范是一个非常有用的规范,因为它支持我们拥有的所有不同布局方法。
虽然display
的许多值都有自己的规范,但display
中详细说明了许多术语和想法。 这意味着理解此规范有助于您理解本质上详细说明display
值的规范。 在本文中,我将看看display
- none
和contents
的框生成值。
一切都是一个盒子
在 CSS 中,一切都会生成盒子。 网页本质上是一组块和内联框,如果您在最喜欢的浏览器中打开 DevTools 并开始选择页面上的元素,您就会很好地理解这一点。 您可以看到构成布局的框,以及如何应用它们的边距、填充和边框。

ul
元素,因此我可以检查盒子的不同部分。 (大预览)控制盒子的生成
display
的none
和contents
值处理是否应该出现框。 如果您的标记中有元素并且不希望它们在 CSS 中生成框,那么您需要以某种方式抑制框的生成。 您可能想做两件事。 哪个是:
- 防止生成一个盒子及其所有子代。
- 防止生成框,但仍显示子项。
我们可以依次看看这些场景中的每一个。
显示:无
display
的none
值是我们如何防止生成一个盒子和该盒子的所有孩子。 就好像该元素根本不存在一样。 因此,它在您打算完全隐藏该内容的情况下很有用,这可能是因为它稍后会在激活链接后显示出来。
如果我有一个带有段落、无序列表和另一个段落的示例,您可以看到这些项目以正常流程显示。 ul
应用了背景和边框,以及一些填充。
请参阅 Rachel Andrew 的 Pen Box Generation 示例。
如果我向ul
添加display: none
,它会从视觉显示中消失,同时ul
的子项以及背景和边框。
请参阅 Rachel Andrew 的 Pen Box Generation 示例显示:无。
如果您使用display: none
它会向网站的所有用户隐藏内容。 这包括屏幕阅读器用户。 因此,只有当您的意图是盒子和里面的所有东西对所有人都完全隐藏时,您才应该使用它。
在某些情况下,您可能希望为屏幕阅读器等辅助技术的用户添加其他信息,但对其他用户隐藏它; 在这种情况下,您需要使用不同的技术。 Scott O'Hara 在他的文章“Inclusively Hidden”中提出了一些很好的建议。
因此,使用display: none
非常简单。 在您希望盒子和内容从显示器、盒子树和可访问性树中消失的情况下使用它(就好像它从一开始就不存在一样)。
显示:内容
对于第二种情况,我们需要查看一个更新的 display 值。 值display: contents
会以与display: none
相同的方式从盒子树中删除它所应用的盒子,但将子元素留在原处。 就我们可以在布局中执行的操作而言,这会导致一些有用的行为。 让我们看一个简单的例子,然后进一步探索。
我使用与以前相同的示例,但这次我在ul
上使用了display: contents
。 列表项现在是可见的,但是,它们没有背景和边框,就像您在页面中添加了li
元素而没有任何封闭的ul
一样。
请参阅 Pen Box Generation 示例显示:Rachel Andrew 的内容。
删除一个盒子并保留孩子很有用的原因是由于display
的其他值的行为方式。 当我们改变display
的值时,我们会在一个盒子和那个盒子的直接孩子上这样做,正如我在上一篇文章中描述的那样。 如果我将display: flex
添加到元素的 CSS 规则中,则该元素将成为块级框,而直接子项将成为 flex 项。 这些 flex 项的子项返回正常流程(它们不是 flex 布局的一部分)。
您可以在下一个示例中看到此行为。 这里我有一个包含元素集来显示 flex,它有四个直接子元素、三个 div 元素和一个ul
。 ul
有两个列表项。 直接子元素都参与了弹性布局并作为弹性项目布局。 列表项不是直接子项,因此在ul
的框内显示为列表项。

查看 Pen Box Generation flexbox 并显示:Rachel Andrew 的内容 1。
如果我们举这个例子并将display: contents
添加到ul
,则该框将从视觉显示中删除,现在孩子们参与了 flex 布局。 您可以看到它们不会成为直系子代。 它们不像 div 和ul
元素那样被直接子通用选择器 ( .wrapper > *
) 选择,并且它们保持给它们的背景。 所发生的只是包含ul
的框已被移除,其他一切都照常进行。
请参阅 Pen Box Generation flexbox 和显示:Rachel Andrew 的内容 2。
如果我们考虑 HTML 中的元素对可访问性和语义数据很重要,但会生成一个额外的框,这可能会阻止我们使用 flex 或网格布局布局内容,这可能具有非常有用的含义。
这不是 CSS “重置”
您可能已经注意到使用display: contents
的一个副作用是元素上的边距和内边距被移除。 这是因为它们与盒子有关,盒子是 CSS 盒子模型的一部分。 这可能会导致您认为display: contents
是快速摆脱元素上的填充和边距的好方法。
这是 Adrian Roselli 在野外发现的一种用途。 他非常担心,写了一篇详细的文章来解释这样做的问题——“ display: contents
不是 CSS 重置。” 他提出的一些问题是由于当前具有显示的浏览器中的一个不幸的可访问性问题:我们将在下面讨论的内容。 然而,即使这些问题得到解决,从盒子树中删除一个元素只是为了摆脱边距和填充有点极端。
如果不出意外,这对网站的未来维护会产生问题,未来的开发人员可能想知道为什么他们似乎无法对这个神秘的盒子应用任何东西——错过了它已被移除的事实! 如果您需要 margin 和 padding 为0
,请帮您未来的自己一个忙,并以一种历史悠久的方式将它们设置为0
。 保留使用display: contents
用于您确实想要删除框的特殊情况。
还值得注意的是display: contents
和 CSS Grid Layout subgrid 之间的区别。 其中display: contents
从显示中完全删除了框、背景和边框,使网格项成为子网格将保持该项上的任何框样式,并且只需通过轨道大小调整,以便嵌套项可以使用相同的网格。 在我的文章“CSS Grid Level 2: Here Comes Subgrid”中了解更多信息。
可访问性问题和显示:内容
目前一个严重的问题是display: contents
对它最有用的东西没有用。 明显的display: contents
是那些需要额外的框来添加标记的情况,使使用屏幕阅读器或其他辅助设备的人更容易理解您的内容。
我们第一个display: contents
的列表中的ul
元素:contents CodePen 就是一个完美的例子。 通过展平标记而不使用列表,您可以获得相同的视觉效果。 但是,如果内容在语义上是一个列表,屏幕阅读器可以最好地理解和读出该列表作为一个列表,那么它应该被标记为一个。
如果您希望子元素成为 flex 或网格布局的一部分,就像ul
的框不存在一样,您应该能够使用display: contents
来魔术框并使其如此——但离开语义到位。 规范说应该是这种情况,
“display
属性对元素的语义没有影响:这些是由文档语言定义的,不受 CSS 影响。 除了会影响元素及其后代的听觉/语音输出和交互性的 none 值之外,display
属性只影响视觉布局:它的目的是允许设计人员自由更改元素的布局行为而不影响底层文档语义。”
正如我们已经讨论过的, none
值确实对屏幕阅读器隐藏了元素,但是display
的其他值纯粹是为了让我们改变事物的视觉显示方式。 他们不应该触及文档的语义。
出于这个原因,我们很多人都惊讶地意识到display: contents
实际上是从实现它的两个浏览器(Chrome 和 Firefox)的可访问性树中删除元素。 因此更改文档语义,使屏幕阅读器在使用display: contents
删除ul
后不知道列表是列表。 这是一个浏览器错误——而且是一个严重的错误。
去年,Hidde de Vries 在他的帖子“使用display:contents
的更易于访问的标记”中写下了这个问题,并帮助提出了针对各种浏览器的问题,以提高认识并让他们进行修复。 Firefox 已部分解决了该问题,但某些元素(例如按钮)仍然存在问题。 该问题正在 Chrome 中积极解决。 WebKit 也有一个问题。 如果您有用于显示的用例,我鼓励您为这些错误加注星标:受问题影响的内容。
在这些问题得到解决并且出现问题的浏览器版本不再使用之前,您在使用 display: content 时需要非常小心,因为任何传达语义信息并需要暴露于辅助技术的内容。 正如阿德里安·罗塞利所说,
“目前,如果您要使用辅助技术进行测试并且可以确认结果对用户有效,请仅使用 display: contents。”
有些地方你可以安全地使用display: contents
而不用担心。 一种是如果您需要添加额外的标记来为旧浏览器中的 flex 布局网格创建回退。 支持display: contents
的浏览器也支持 grid 和 flexbox,因此你可以display: contents
去掉多余的div
元素。 在下面的示例中,我创建了一个基于浮动的网格,并带有行包装器。
然后我使用display: contents
删除行包装,以允许所有项目成为网格项目,因此能够成为网格布局的一部分。 这可以在为高级布局创建后备时为您提供一个额外的工具,如果您确实需要添加额外的标记,您可以在执行网格或弹性布局时使用 display: contents 删除它。 我不认为这种用法会导致任何问题——尽管如果有人比我有更好的可访问性信息并且可以指出问题,请在评论中这样做。
请参阅 Rachel Andrew 的 Pen Removing row wrappers with display: contents。
包起来
本文研究了display
属性的框生成值。 我希望你现在理解display: none
的不同行为——它完全删除一个盒子和所有的孩子,而display: contents
只删除盒子本身。 您还应该了解在涉及可访问性时使用这些方法的潜在问题。