🐈‍⬛

display: contents; を 1 ミリ以上知りたい人へ

2023/12/24に公開

この記事で分かること

display: contents; がどのような場面で有用かを解説します。
レスポンシブデザインや、 PC と SP で HTML 構造(ファイルなど)を共有しつつ、レイアウトは個別で行いたいというケースを例に用います。

前提

HTML 構造は共通で、以下のような見せ方をします。

large

PC

small

SP

デモ

resize で横に縮めることができます。 width: 500px; がブレークポイントです。

解説

まずは large のレイアウトを基に考えてみます。

  1. 画像(左)
  2. テキスト(右)

大まかに、このように分けられそうです。枠線で表すところの緑と青です。
テキストエリアを div などで囲って、 liflex で横並びにすればほぼ完成です。簡単ですね。

<li>
  <img src="https://placehold.jp/3d4070/ffffff/500x500.png?text=Black%20Mage" alt="黒魔道士" />
  <div>
    <h2>黒魔道士</h2>
    <p>火力が正義だぜ!そうだろ!?</p>
  </div>
</li>

ここから、 HTML 構造を変えずに small の見た目を変えていきましょう。

  1. 見出し
  2. 画像
  3. 説明文

先ほどとは表示順が変わりました。ひとまとまりだったテキスト項目が、画像をサンドイッチするように配置されています。
項目の並び順を CSS で指定する方法は、どのようなものがあるでしょうか?
そうです、 display: flex;order を組み合わせれば良いのです。
https://developer.mozilla.org/ja/docs/Web/CSS/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;
  }
}

先述のように、本来であれば h2p など HTML 上で div に阻まれているものは、 liorder の対象になることはできません。
しかし、 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 以下のとき、 divdisplay: contents; を付与する」という条件をつけているため、
ブレークポイントに依るレイアウトの変化も万全にサポートすることができます。

おわりに

セマンティックマークアップが声高に叫ばれる昨今、「見せ方の都合上セマンティックを担保できないんだよね、仕方ないね」という方便もなかなか通用しなくなってきました。
そのような葛藤の最中、 display: contents; によって救われる場面も多々あるのではないかなと思います。
「こいつが無ければ上手くいくのになぁ」とフラストレーションを抱いたとき、 display: contents; くんの存在を思い出していただければ、もしかしたらこの CSS が貴方の英雄になってくれるかもしれません。

Discussion