display: contents; を 1 ミリ以上知りたい人へ
この記事で分かること
display: contents;
がどのような場面で有用かを解説します。
レスポンシブデザインや、 PC と SP で HTML 構造(ファイルなど)を共有しつつ、レイアウトは個別で行いたいというケースを例に用います。
前提
HTML 構造は共通で、以下のような見せ方をします。
large
small
デモ
resize
で横に縮めることができます。 width: 500px;
がブレークポイントです。
解説
まずは large のレイアウトを基に考えてみます。
- 画像(左)
- テキスト(右)
大まかに、このように分けられそうです。枠線で表すところの緑と青です。
テキストエリアを div
などで囲って、 li
の flex
で横並びにすればほぼ完成です。簡単ですね。
<li>
<img src="https://placehold.jp/3d4070/ffffff/500x500.png?text=Black%20Mage" alt="黒魔道士" />
<div>
<h2>黒魔道士</h2>
<p>火力が正義だぜ!そうだろ!?</p>
</div>
</li>
ここから、 HTML 構造を変えずに small の見た目を変えていきましょう。
- 見出し
- 画像
- 説明文
先ほどとは表示順が変わりました。ひとまとまりだったテキスト項目が、画像をサンドイッチするように配置されています。
項目の並び順を CSS で指定する方法は、どのようなものがあるでしょうか?
そうです、 display: flex;
と order
を組み合わせれば良いのです。
しかし、ここで大きな問題が発生します。 order
は、 flex
の直下でないと効力を発揮しないのです。
large のレイアウトで、「左」と「右」で項目を分けて配置するために、テキスト群は div
で囲われています。要はこいつが邪魔なのです。
div
を消し去れたらいいのに…さながら全てを破壊し尽くす黒魔法のように……。
とまではいきませんが、 div
を「なかったことにする」スキルが display: contents;
です。
CSS を抜粋して見てみましょう。
ul {
container: jobs / inline-size;
}
li {
display: flex;
}
@container jobs (max-width: 500px) {
li {
flex-direction: column;
}
div {
display: contents;
}
h2 {
order: 1;
}
img {
order: 2;
}
p {
order: 3;
}
}
先述のように、本来であれば h2
や p
など HTML 上で div
に阻まれているものは、 li
の order
の対象になることはできません。
しかし、 display: contents;
を指定することによって、この div
の存在をスキップすることができるのです。
CSS の目線で表すと、このようになります。
<!-- CSS 目線でのイメージ -->
<li> <!-- flex container -->
<img src="https://placehold.jp/3d4070/ffffff/500x500.png?text=Black%20Mage" alt="黒魔道士" />
<!-- div?? 知らない名前ですね… -->
<h2>黒魔道士</h2>
<p>火力が正義だぜ!そうだろ!?</p>
</li>
li
とテキスト群の間に阻むものがなければ、 order
も思う存分発動することができますね!
このデモでは「コンテナが 500px 以下のとき、 div
に display: contents;
を付与する」という条件をつけているため、
ブレークポイントに依るレイアウトの変化も万全にサポートすることができます。
おわりに
セマンティックマークアップが声高に叫ばれる昨今、「見せ方の都合上セマンティックを担保できないんだよね、仕方ないね」という方便もなかなか通用しなくなってきました。
そのような葛藤の最中、 display: contents;
によって救われる場面も多々あるのではないかなと思います。
「こいつが無ければ上手くいくのになぁ」とフラストレーションを抱いたとき、 display: contents;
くんの存在を思い出していただければ、もしかしたらこの CSS が貴方の英雄になってくれるかもしれません。
Discussion