display: contents
是一個比較陌生的屬性,雖然屬於 display 這個基本上是最多見的 CSS 屬性,可是 contents
這個取值基本不會用到。可是它早在 2016 年就已經獲得了 Firefox 的支持。css
本文將深刻一下這個有意思的屬性值。html
根據 W3C 對 display: 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
這個很是好理解,可是若是,咱們給中間層的容器添加上 display: contents
,再看看效果:佈局
<div class="container">
<div class="wrap" style="display: contents">
<div class="inner"></div>
</div>
</div>
複製代碼
能夠看到,沒有了中間層的 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: flex
、display: 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>
若是包裹了內容,其一些可繼承樣式仍是會被子內容繼承。這個實際使用的過程當中須要注意一下。
在一些外文文檔中有一些討論是關於 display: contents
的使用會影響到頁面的可訪問性。例如做用了 display: contents
的容器及列表,會對頁面的可訪問性帶來一些意外結果。
這個我看暫時沒有明確的結論,若是你的頁面對可訪問性的要求很高,具體使用的此屬性的話也是須要注意一下這一點。
CSS 自己其實也在一直在努力,增長了各類屬性去讓咱們在佈局上有更多的空間與控制權。總而言之給個人感覺是讓 CSS 更加的像是一個完整的工程而不只僅只是展示樣式。
相似的一些有意思的屬性:
看看兼容性。
不算太慘淡,但也不算全面普及。考慮用在一些漸進加強的場景當中。
好了,本文到此結束,但願對你有幫助 :)
更多精彩 CSS 技術文章彙總在個人 Github -- iCSS ,持續更新,歡迎點個 star 訂閱收藏。
更多精彩有趣的 CSS 效果,歡迎來這裏看看 CSS 靈感 -- 在這裏找到寫 CSS 的靈感。
若是還有什麼疑問或者建議,能夠多多交流,原創文章,文筆有限,才疏學淺,文中如有不正之處,萬望告知。