【CSS】display: contents の使用方法!便利な使い方を例を交えて解説します

今回は「display: contents」について解説します。

displayプロパティはよく使用すると思いますが、contentsを指定したことはありますか?

理解を深められれば、レスポンシブでよくある少し戸惑うようなレイアウトも簡単に実装することができます。

使用する際の注意点もあるので、今回をきっかけに深堀していきましょう。

display: contents について

The element itself does not generate any boxes, but its children and pseudo-elements still generate boxes and text sequences 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).

CSS Display Module Level 3

翻訳すると下のような文章になります。

「要素自体はボックスを生成しませんが、その子要素や擬似要素は通常通りボックスやテキスト列を生成します。ボックスの生成とレイアウトのために、要素は、要素ツリーでその内容(そのソースドキュメントの子とその擬似要素(例: ::before や ::after 擬似要素など、通常通り要素の子の前/後に生成される)の両方が置き換えられたかのように扱われなければなりません。」

わかるような、わからないような・・・という感じですよね。

詳しく説明していくために、まずはボックスの概念を理解しておく必要があります。

display:contensはボックスを生成しない

HTMLの要素は箱のようなボックスになっています。

margin,padding,borderの図

ボックスはコンテンツの幅や高さ、border、padding、marginで構成されています。

実際にマークアップすると以下のようになります。

<div class="wrapper">
  <p>コンテンツ</p>
</div>

.wrapperにborder、padding、marginを指定してみます。(分かりやすいようにbackground-colorも指定)。

.wrapper {
  margin: 30px;
  padding: 30px;
  border: 1px solid #000;
  background-color: #ddd;
}

ブラウザでは、以下のように表示されます。

では、wrapperクラスに「display:contents」を指定したらどうなるでしょうか。

.wrapper {
  display: contents;
  margin: 30px;
  padding: 30px;
  border: 1px solid #000;
  background-color: #ddd;
}

答えはこちらです。

border、padding、margin(、background-color)がなくなって中身だけになりました。

これが引用元の文章の「要素自体はボックスを生成しませんが、その子要素や擬似要素は通常通りボックスやテキスト列を生成します。」という部分です。

display: contentsを指定すると、指定された要素はボックスを生成しません

なので、divタグのwrapperクラスはブラウザで表示されなくなり(HTMLでは表示され続ける)、その中にあるpタグだけが表示されます。

これが display: contents です。

上記の例で、.wrapperにfont-sizeなど子要素に継承されるプロパティを指定した場合、その値は子要素に継承されます。

display:noneとの違い

display: contentsと同様に、表示しない方法として display: none がありますが、この二つはどう違うのでしょうか。

  • display: contents → 指定したタグのボックスを生成しない
  • display: none → 指定したタグのボックス全て(中身も)生成しない

指定のボックスだけか、ボックスの中身も含めた全体かという点が大きい違いです。

また、display: contentsはHTMLに表示が残りますが、display: noneはHTMLからも無くなるという違いもあります。

使用用途に合わせて使い分けしましょう。

display: contents を使用すると便利なところ

display: contentsを使用することで、レスポンシブでよくある少し戸惑うようなレイアウトも簡単に実装することができます。

例えば、このようなレイアウトの場合です。

モバイルでは「タイトル→写真→説明文」となっているレイアウトが、パソコンでは「左に写真→右にタイトル・説明文」となっています。

この場合、皆さんはどのようにマークアップしますか?

結構悩みますよね・・・。

モバイルのレイアウトに合わせてマークアップすると、パソコンのレイアウトにするときに横並びにしたらタイトルと説明文が離れてしまいます。

逆に、パソコンのレイアウトに合わせてもモバイルの時に画像の位置に困ると思います。

その時に使用すると便利なのが display: contents です。

実際の使用例を見てみましょう。

display: contents の使用例

以下のデモページで実際の動きを確認できます。

実際に画面幅を動かして挙動を確認してみてください。

モバイルの時は「タイトル→写真→説明文」の順で上から並ぶレイアウトになっています。

パソコンの時は「左に写真→右にタイトル・説明文」のレイアウトになっています。

では、コードはどうなっているのでしょうか。

実際のコードを下記に記述しますので参考にしてみてください。

  <section class="card">
    <div class="card__text-group">
      <h2 class="card__title">タイトル</h2>
      <p class="card__description">
        説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文
      </p>
    </div>
    <figure class="card__media">
      <img src="./images/photo.jpg" alt="マットの上で運動をする姿" width="624" height="416">
    </figure>
  </section>

PCサイズでは問題ありませんが、スマホではタイトルと説明文の間に画像を入れなくてはいけません。

そのままだと画像はcard__text-groupの外にあるので、orderを使っても間に入れることはできません。

  <section class="card">
    <div class="card__text-group"><!-- ←このタグがなければorderで順番を変えられる -->
      <h2 class="card__title">タイトル</h2>
      <p class="card__description">
        説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文説明文
      </p>
    </div><!-- ←このタグがなければorderで順番を変えられる -->
    <figure class="card__media">
      <img src="./images/photo.jpg" alt="マットの上で運動をする姿" width="624" height="416">
    </figure>
  </section>

.card__text-groupdisplay: contentsを当てることで、まるで.card__text-groupが存在しないかのように振る舞わせることができます。

実際のCSSの記述はこちらです。

.card {
  background-color: #eee;
  padding: 16px;
  display: flex;
  flex-direction: column;
}

.card__text-group {
  display: contents; //スマホサイズではボックスを生成しない
}

.card__title {
  margin: 0 0 1em;
}

.card__description {
  order: 1;
  margin: 0 0 1em;
}

.card__media {
  margin: 0;
}

.card__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

@media (min-width: 768px) {
  .card {
    flex-direction: row;
    padding: 32px;
    column-gap: 16px;
  }

  .card__text-group {
    display: block;
    order: 1;
    flex: 1;
  }

  .card__description {
    order: 0;
  }

  .card__media {
    flex: 1;
  }
}

この方法を知っていれば、無駄な記述が少なくて済みますし時短にもなります。(実際に今回は5分で実装できました)

対応ブラウザ

対応ブラウザに関してはこちらをご覧ください。

IEは非対応ですが、IEのサポートは終了しているので、気にする必要はありません。

2023年4月13日現在、主要ブラウザで完全対応ではないため、後述する注意点もあります。

注意点

とても便利な display: contents ですが、注意点があります。

As of writing, however, this is not implemented correctly in major browsers, so using this feature on the Web must be done with care as it can prevent accessibility tools from accessing the element’s semantics.

CSS Display Module Level 3

翻訳するとこうなります。

「ただし、執筆時点では、主要なブラウザで正しく実装されていないため、Web上でこの機能を使用すると、アクセシビリティツールが要素のセマンティクスにアクセスできなくなる可能性があるため、注意が必要である。」

アクセシビリティツールは目が見えないユーザーが使用する「文章読み上げツール」のことだと考えられます。

その「文章読み上げツール」が display: contentsを指定した中身の要素にアクセスできなくなる可能性があるということです。

display: contentsはまだ新しい方なので順次対応していくと思いますが、アクセシビリティツールを考えると使用はできるだけ最小限にした方が良いのかもしれません。

「文章読み上げツール」が display: contents を指定した中身の要素にアクセスできなくなる可能性がある!

まとめ

今回は「display: contents」について解説しました。

レスポンシブでよくある少し戸惑うようなレイアウトも簡単に実装することができましたね。

使用を考えた際はブラウザの状況を見ながら、アクセシビリティツールにも配慮して使用するかを判断しましょう。

少し使用する際は注意が必要ですが、とても便利なのでぜひ覚えておいてください。


その他の記事