画面幅によりコンテンツの配置や順序が大きく変わるデザインに対して、HTMLに記述する階層構造は変えずにCSSだけで対応したい。
この記事では下図のレイアウトを題材にします。1つのセクションの中に、見出し1個、画像2個、テキストの段落4個を配置したページです。レイアウトはデスクトップ向け、タブレット向け、およびスマホ向けの3種類です。
※画像引用: Photo by Johnny Africa on Unsplash, Photo by Katja Rooke on Unsplash
これを実現するため、最初にデスクトップ向けレイアウトのコーディングだけを考えてみます(下図の左側)。そこで、画像を囲むdiv.b、本文のp要素を囲むテキストブロックをdiv.cとし、div.bとdiv.cをコンテナdiv.aで包み、さらにテキストを回り込ませるためdiv.bをfloatで配置しました。
では、同じマークアップを使ってタブレット向けレイアウトにCSSで対応させるには? div.bをflexboxにしてimg要素を横並びにし、section(一番外側の赤い枠)をflexboxにして、アイテムを縦並び、アイテムの順番をorderで変えて見出しh2を2番目に...ダメです。デスクトップ用に入れたコンテナdiv.aが"壁"になってしまい、h2をdiv.bとdiv.cと同じ階層に持っていくことができません。
スマホ向けレイアウトの場合はどうでしょう。こちらは2つ目のimg要素がp要素の並びに挿入された形をしています。今度はデスクトップ用に入れたdiv.bとdiv.cの壁が邪魔です。これらのdivを"解体"して子要素に分解しないといけませんね。
HTMLに記述した階層構造は変えずにdivの"壁"だけ撤去したい...こんな時に役立つのが、CSSのdisplay
プロパティのcontentsキーワードです。
ソースコードはこちら: https://codepen.io/kaz_hashimoto/pen/oNqMPor
このCodePenは、HTMLの同じマークアップから11種類のレイアウトを生成します。レイアウトの切り替えは、JavaScriptを使ってsection
要素にclassを設定することにより行います。レイアウトの種類を表すclass名は "layout1"〜"layout11"です。レイアウトの種類に応じて、div.group1, div.group2, div.group3の表示種別(CSSのdisplay
プロパティの値)が変化します: block
, grid
, flex
, contents
。
<section class="section layout1">
<h2>Section 1</h2>
<div class="group1">
<div class="group2">
<div class="photo">
<img src="photo1.jpg">
</div>
<div class="photo">
<img src="photo2.jpg">
</div>
</div>
<div class="group3">
<p class="text">1. ....</p>
<p class="text">2. ....</p>
<p class="text">3. ....</p>
<p class="text">4. ....</p>
</div>
</div>
</section>
このテクニックを用いて、冒頭に示したレスポンシブ対応のレイアウトを実装したのがこちらのDEMOです。classの代わりにメディアクエリーでスタイルを上書きしてレイアウトを切り替えています。
※上記CodePenのlayout3, layout5, およびlayout7に相当します。
DEMO: https://codepen.io/kaz_hashimoto/pen/RwMeeXp
See the Pen [video] Responsive layout with css display: contents by Kazuhiro Hashimoto (@kaz_hashimoto) on CodePen.