display: contents; を設定した要素は、DOMツリー(アクセシビリティツリー)から削除される。
省略されるのはcontentsを指定した要素のみで、子孫要素へは影響を与えない。
display: contents の値を設定すると、指定した要素のコンテンツ領域以外は描画されなくなる。
<p>テキスト</p>
コンテンツ領域とはタグで囲んだ中身のことで、上記であればpタグの中にある「テキスト」という文字のこと。
つまり、その他のpadding・border・marginがブラウザに描画されなくなる、ということである。
display:none との違い
ブラウザに対する非表示指定の値としては「none」もあるが、違いは『コンテンツ領域を表示するか・しないか』である。
display: contents はコンテンツ領域(pタグと「テキスト」という文言)を描画しているのに対し、display: none はコンテンツ領域含めすべて描画されない。
検証ツールで確認してみても、display: contents を指定したdiv要素は選択できないが、子要素にあたるpタグは選択することができる。
これはブラウザに描画されなくなる要素が、display: contents を指定した要素のみに限定されていることを意味している。
display: contents のメリット
- HTMLを構造化できる
- 不要なラッパー要素となるHTMLを省略できる
display: contents の実装例
FlexBoxとの組み合わせ
display: flexを使用して、以下のようなボックスを作成する。
<div class="container">
<img class="thumbnail" src="thumbnail.png" alt="">
<div class="contents">
<h2 class="title">ブログのタイトルが入ります。</h2>
<p class="text">ブログの説明が入ります。</p>
<button type="button" class="button">Enter</button>
</div>
</div>
上記のdivタグ(contentsクラス)にdisplay: contentsを指定する。
@media screen and (max-width:600px) {
.contents {
/* align-items: center; */
display: contents;
}
}
divタグ(contentsクラス)にdisplay: contentsを指定したことで、containerクラスの子要素(フレックスアイテム)は以下のように変化する。
同時に検証ツール上(DOM)でもcontentsクラスのdivタグが触れなくなっている。
実際のHTMLコードが変わっているわけではないが、DOM上だと以下のような振る舞いになる。
画像以外の要素を囲んでいたdivタグ(contentsクラス)をdisplay: contentsで認識させなくしたことで、4つのタグが兄弟要素のように扱われる。
フレックスアイテム | |
display: contents指定前 | imgタグ・divタグ(contentsクラス) |
display: contents指定後 | imgタグ・h2タグ・pタグ・buttonタグ |
<div class="container">
<img class="thumbnail" src="thumbnail.png" alt="">
<h2 class="title">ブログのタイトルが入ります。</h2>
<p class="text">ブログの説明が入ります。</p>
<button type="button" class="button">Enter</button>
</div>
同列のフレックスアイテムとなったtitleクラスのh2タグに、orderプロパティを指定する。
orderプロパティを指定することで、フレックスコンテナ内での並びを変えることができる。
@media screen and (max-width:600px) {
.title {
font-size: 20px;
order: -1;
}
}
order: -1を指定したことで、titleクラス(h2タグ)の順番を、imgタグより上に移動させることができる。
ブラウザが認識する要素の階層が変わることで、フレックスアイテムも変化し、元のHTML階層では干渉できなかった要素へ影響を与えることが可能となる。
Gridレイアウトとの組み合わせ
display: gridと組み合わせてソースを簡略化することもできる。
<div class="table">
<div class="required">必須</div>
<div class="contents">必須項目の記載をここに行う</div>
<div class="required">必須</div>
<div class="contents">必須項目の記載をここに行う</div>
<div class="optional">任意</div>
<div class="contents">任意項目の記載をここに行う</div>
<div class="optional">任意</div>
<div class="contents">任意項目の記載をここに行う</div>
<div class="required">必須</div>
<div class="contents">必須項目の記載をここに行う</div>
</div>
.table {
width: 500px;
margin: 20px auto 0;
display: grid;
grid-template-columns: repeat(2, auto);
border-top: solid 1px #000;
}
.required {
text-align: center;
color: #ff0000;
border-bottom: solid 1px #000;
}
.optional {
text-align: center;
color: #0000ff;
border-bottom: solid 1px #000;
}
.contents {
text-align: center;
border-bottom: solid 1px #000;
border-left: solid 1px #000;
}
表の行や列が増えてくるとHTMLからテーブルの構造が分かりづらくなる。
そこで各行にrowクラスを付与した親要素を追加してテーブルの行をまとめ、それぞれにCSSでdisplay: contentsを指定する。
<div class="table">
<div class="row">
<div class="required">必須</div>
<div class="contents">必須項目の記載をここに行う</div>
</div>
<div class="row">
<div class="required">必須</div>
<div class="contents">必須項目の記載をここに行う</div>
</div>
<div class="row">
<div class="optional">任意</div>
<div class="contents">任意項目の記載をここに行う</div>
</div>
<div class="row">
<div class="optional">任意</div>
<div class="contents">任意項目の記載をここに行う</div>
</div>
<div class="row">
<div class="required">必須</div>
<div class="contents">必須項目の記載をここに行う</div>
</div>
</div>
/* 追加 */
.row {
display: contents;
}
display: gridを指定したはじめの状態では、各行が縦並びになっているが、grid-template-columns: repeat(2, auto)を指定することで、2列のグリッドラインができ、rowクラスの要素がグリッド上に並ぶ。
その後、グリッドアイテムとなっていたrowクラスにdisplay: contentsを指定することで、子階層の各要素がグリッドアイテムに変化し、デザイン通りのレイアウトとなる。
display: contentsを指定することで、グリッドコンテナ(tableクラス)の影響を受けずレイアウトができる。