巧用 display: contents 加强页面语义

display: contents 是一个比较陌生的属性,虽然属于 display 这个基本上是最多见的 CSS 属性,可是 contents 这个取值基本不会用到。可是它早在 2016 年就已经获得了 Firefox 的支持。css

本文将深刻一下这个有意思的属性值。html

基本用法

根据 W3Cdisplay: contents 的定义。git

The element itself does not generate any boxes, but its children and pseudo-elements still generate boxes and text runs as normal. For the purposes of box generation and layout, the element must be treated as if it had been replaced in the element tree by its contents (including both its source-document children and its pseudo-elements, such as ::before and ::after pseudo-elements, which are generated before/after the element’s children as normal).github

简单翻译一下便是,将设置了该属性值的元素自己将不会产生任何盒子,可是它的从保留其子代元素的正常展现。canvas

看个简单的例子。有以下简单三层结构:app

<div class="container">
    <div class="wrap">
        <div class="inner"></div>
    </div>
</div>
复制代码

简单的 CSS 以下:框架

.container {
    width: 200px;
    height: 200px;
    background: #bbb;
}

.wrap {
    border: 2px solid red;
    padding: 20px;
    box-sizing: border-box;
}

.inner {
    border: 2px solid green;
    padding: 20px;
    box-sizing: border-box;
}
复制代码

表现以下:ide

image

这个很是好理解,可是若是,咱们给中间层的容器添加上 display: contents,再看看效果:布局

<div class="container">
    <div class="wrap" style="display: contents">
        <div class="inner"></div>
    </div>
</div>
复制代码

image

能够看到,没有了中间层的 border: 2px solid red 的红色边框,整个 .wrap div 好像不存在同样,可是它的子元素倒是正常的渲染了。flex

重点,设置了display: contents的元素自己不会被渲染,可是其子元素可以正常被渲染

这个属性我一直在思考有什么很是适合的使用点。

总结来讲,这个属性适用于那些充当遮罩(wrapper)的元素,这些元素自己没有什么做用,能够被忽略的一些布局场景。

充当无语义的包裹框

最近写 React、Vue 的时候,发现这个属性在写 JSX 的时候能有很好的做用,而且也很是符合这个属性自己的定位。

咱们在写 React、RN 时,常常须要输出一段模板。

return (
    <div class="wrap"> <h2>Title</h2> <div>...</div> </div>
)
复制代码

咱们只是想输出 .wrap div 内的内容,可是因为框架要求,输出的 JSX 模板必须包含在一个父元素之下,因此不得已,须要添加一个 .wrap 进行包裹,可是这个 .wrap 自己是没有任何样式的。

若是输出的元素是要放在其余 display: flexdisplay: grid 容器之下,加了一层无心义的 .wrap 以后,整个布局又须要从新进行调整,麻烦。

一种方法是使用框架提供的容器 <React.Fragment>,它不会向页面插入任何多余节点。

在 Vue 中相似的是 <template> 元素, <template> 也是不会被渲染在 DOM 树中,查看页面结构也没法看到,可是 display: contents 是存在于页面结构中的,只是没有生成任何盒子。

这个多出来的父元素实际上是不必的。这个时候,咱们也能够添加上 display: contents,像是这样:

return (
    <div class="wrap" style="display: contents"> <h2>Title</h2> <div>...</div> </div>
)
复制代码

这样,它既起到了包裹的做用,可是在实际渲染中,这个 div 其实没有生成任何盒子,一箭双雕。而且像一些 flex 布局、grid 布局,也不会受到影响。

Codepen Demo -- display: contents | display: flex 的穿透影响

让代码更加符合语义化

考虑这个很是实际的场景,如今咱们的页面上充斥了大量的可点击按钮,或者点击触发相应功能的文字等元素。可是,从语义上而言,它们应该是一个一个的 <button>,可是实际上,更多时候咱们都是使用了 <p>、<div>、<a> 等标签进行了模拟,给他们加上了相应的点击事情而已。

像是下面这样,虽然没什么问题,可是相对而言不那么符合语义化:

<p class="button">
    Button
</p>
<p class="button">
    Click Me
</p>
复制代码
.button {
    width: 120px;
    line-height: 64px;
    text-align: center;
    background-color: #ddd;
    border: 2px solid #666;
}
复制代码

咱们不使用 <button> 的缘由有不少,<button> 相对 div 而言没那么好控制,且会引入不少默认样式。可是,有了 display: contents,咱们可让咱们的代码既符合语义化,同时不须要去解决 <button> 带来的一些样式问题:

<p class="button">
    <button style="display: contents">
        Button
    </button>
</p>
<p class="button">
    <button style="display: contents">
        Click Me
    </button>
</p>
复制代码

添加了 <button style="display: contents">Click Me</button> 的包裹,不会对样式带来什么影响,button 也不会实际渲染在页面结构中,可是页面的结构语义上好了很多。

CodePen Demo -- Button with display: contents

对于对页面结构、语义化有强迫症的一些同窗而言,灵活运用这个属性能够解决不少问题。

在替换元素及表单元素中一些有意思的现象

display: contents 并不是在全部元素下的表现都一致。

对于可替换元素及大部分表单元素,使用 display: contents 的做用相似于 display: none

也就是说对于一些常见的可替换元素、表单元素:

  • <br>
  • <canvas>
  • <object>
  • <audio>
  • <iframe>
  • <img>
  • <video>
  • <frame>
  • <input>
  • <textarea>
  • <select>

做用了 display: contents 至关于使用了 display: none ,元素的整个框和内容都没有绘制在页面上。

<button> 的一些异同

与其余表单元素不同,正常而言,添加了 display: contents 至关于被隐藏,不会被渲染。可是实际运用过程当中发现,<button></button> 若是包裹了内容,其一些可继承样式仍是会被子内容继承。这个实际使用的过程当中须要注意一下。

对 A11Y 的影响

在一些外文文档中有一些讨论是关于 display: contents 的使用会影响到页面的可访问性。例如做用了 display: contents 的容器及列表,会对页面的可访问性带来一些意外结果。

这个我看暂时没有明确的结论,若是你的页面对可访问性的要求很高,具体使用的此属性的话也是须要注意一下这一点。

CSS 中相似的一些影响布局的属性

CSS 自己其实也在一直在努力,增长了各类属性去让咱们在布局上有更多的空间与控制权。总而言之给个人感觉是让 CSS 更加的像是一个完整的工程而不只仅只是展示样式。

相似的一些有意思的属性:

CAN I USE

看看兼容性

image

不算太惨淡,但也不算全面普及。考虑用在一些渐进加强的场景当中。

参考

最后

好了,本文到此结束,但愿对你有帮助 :)

更多精彩 CSS 技术文章汇总在个人 Github -- iCSS ,持续更新,欢迎点个 star 订阅收藏。

更多精彩有趣的 CSS 效果,欢迎来这里看看 CSS 灵感 -- 在这里找到写 CSS 的灵感

若是还有什么疑问或者建议,能够多多交流,原创文章,文笔有限,才疏学浅,文中如有不正之处,万望告知。

相关文章
相关标签/搜索