fieldset要素とlegend要素の記事でCSSの設定をする際にdisplay: contents を使いましたが、その際にdisplay: contents について調べたことをメモしておきます。
display: contents について
MDNのページ内では以下のように説明されています。
contents
これらの要素は自身のために特定のボックスを生成しません。擬似ボックスやその子ボックスで置き換えられます。なお、 CSS Display Level 3 仕様書では、
contents
の値が「普通ではない要素」 — 置換要素のように、 CSS ボックスの純粋な概念に従って表示されない要素に影響する方法を定義しています。詳しくは Appendix B: Effects of display: contents on Unusual Elements を参照してください。
display: contents を設定する場合と設定しない場合で、実際に表示がどう変わるのかを試してみます。
<div class="contents">display: contents</div> <div class="not-contents">display: block</div>
2つの要素に対して複数のプロパティと疑似要素を設定します。
.contents, .not-contents { width: 500px; margin: 30px; border: 5px solid purple; padding: 20px; color: pink; font-size: 32px; background-color: orange; } .contents::before, .not-contents::before { content: 'before'; margin-inline: 10px; } .contents::after, .not-contents::after { content: 'after'; margin-inline: 10px; } .contents { display: contents; } .not-contents { display: block; }
display: contents のデモページ
デモを見ると、display: contents を設定した方は文字色や疑似要素の指定は効いていますが、余白や背景色などの指定が効いていないことが確認できます。
前述の引用にもあるように、display: contents を設定した要素はボックスを生成しないため、その要素に対するCSSの設定(余白や幅、背景色など)も適用されません。
ただ、その疑似要素や子孫要素は通常通り表示されるので、文字色や文字サイズは継承されてCSSが適用されます。
対応ブラウザ
display: contents の対応ブラウザはこちらで、基本的には主要ブラウザで対応していますが、ボタンに対してdisplay:contents が適用されると、アクセスできなくなるという問題があるようです。
実際に動作を確認してみます。
<p>通常時</p> <a href="#">リンク</a> <form action="./" method="get"> <button type="submit">ボタン</button> </form> <p>display: contents の場合</p> <a style="display: contents;" href="#">リンク</a> <form action="./" method="get"> <button style="display: contents;" type="submit">ボタン</button> </form>
マウス操作でのクリック時はどちらも問題なく動作していますが、Tabキーでのキーボード操作時はdisplay: contents の方はフォーカスできません。
ボタンにdisplay: contents を設定するデモページ
使用例
使用例としては、以前投稿したfieldset要素の装飾の記事のように、fieldset要素とlegend要素の装飾時に使えます。
<div class="form-parts"> <fieldset> <legend class="form-parts_key">好きな食べ物</legend> <div class="form-parts_item"> <input type="checkbox" name="check[]" id="check-a" value="鯖の味噌煮"> <label for="check-a">鯖の味噌煮</label> <input type="checkbox" name="check[]" id="check-b" value="ビビンバ"> <label for="check-b">ビビンバ</label> <input type="checkbox" name="check[]" id="check-c" value="鶏そぼろ丼"> <label for="check-c">鶏そぼろ丼</label> <input type="checkbox" name="check[]" id="check-d" value="丼もの"> <label for="check-d">丼もの</label> </div> </fieldset> </div>
fieldset要素に対してdisplay: flex や display: grid が正しく適用されないため、ラッパー要素に対して設定を行い、fieldset要素には display: contents を設定します。
.form-parts { display: grid; grid-template-columns: 140px 1fr; } .form-parts > fieldset { display: contents; }
他の例として、PCの場合は画像とテキスト群を左右に並べるレイアウト、SP時は縦並びで画像の上下にテキストが分かれて配置されるレイアウトなどにも使用できます。
<div class="profile"> <div class="profile_img"></div> <div class="profile_text"> <p class="profile_name">リゼ・ヘルエスタ</p> <p class="profile_group">さんばか</p> <p class="profile_description">ヘルエスタ王国の第二皇女。文武両道学園主席、真面目で誰にでも優しくかなりの人望がある。<br>王位継承の資格者として日々鍛錬や人とのコミュニケーションを大事にしている。</p> </div> </div>
今回の例だとdisplay: grid を使えばdisplay: contents 無しでも実装できそうですが、display: flex で実装する想定で試してみます。
CSSは必要な部分のみ抜粋しています。
.profile { display: flex; flex-direction: column; align-items: flex-start; } @media (min-width: 768px) { .profile { flex-direction: row; gap: 20px; } } .profile_img { order: 3; flex-shrink: 0; } .profile_text { display: contents; } @media (min-width: 768px) { .profile_text { display: block; order: 4; } } .profile_name { order: 1; } .profile_group { order: 2; } .profile_description { order: 4; }
SP時に .profile_text にdisplay: contents を設定して、その中の各テキスト要素にorderを設定することで並び順の制御を行っています。
PCとSPでのレイアウト変更に対応するデモページ
コメントが承認されるまで時間がかかります。