🐷

CSS gridで<div>をでネストしても良い

に公開1

CSS grid に関してよく言われるメリットのひとつに、(CSS grid 以前から存在していた CSS flex と比べて)不必要にネストした<div>を使わなくて良くなる、というものがあります。これによって HTML の構造がシンプルできれいになるというわけです。

このメリット自体は正しいのですが、私の場合なぜか CSS grid の使い方を練習するうちに、いつの間にか誤解してしまい「ネストした<div>を極力避けなければならない」と思いこむようになっていました。

極端な姿勢でネストした<div>を避けることは、本来もっと楽な書き方があるのに無駄に苦労して HTML や CSS を書くことになり、書くスピードが落ちてしまいかねません。また React では<div>のネストに伴い、コンポーネントもネストさせることで、見やすくて責任範囲の限定された扱いやすいコンポーネントを実現できます。

本記事では CSS grid を使う上で「必要な<div>のネスト」には十分なメリットがあること、必要以上に<div>のネストを忌避しなくてもよいことを説明します。

不必要にネストした<div>とは?

そもそも CSS grid では使わなくて良くなった「不必要にネストした<div>」とは、CSS flex で複雑なレイアウトを実現するときによく使われていたものです。それらは CSS grid 登場後に「同じレイアウトを CSS grid で実現すると、一部の<div>のネストが不要になる」という例が複数認識されることによて、CSS flex と grid の差として認識されることになりました。

この問題に関する言及を、いくつかの書籍から挙げます

1. 作って学ぶ HTML + CSS グリッドレイアウト エビスコム著、マイナビ出版、2024 年

こちらの書籍は私が CSS grid を使うためにいつも頼りにしている教科書的な書籍です。

chapter 2 の 3「フローレイアウトとフレックスボックスでは不十分だったレイアウト制御」より

「ネストされたフレックスボックスがたくさん必要になる」というのはどういう状況でしょうか?たとえば p.61 のサンプルで、カラム落ちさせたボタンを画像の下ではなく、横に並べることを考えてみます ⋯(中略)⋯ ネストを重ねていけば複雑なレイアウトも構築できることがわかります。⋯(中略)⋯ ですが、レイアウトを少し調整しようとしただけで DOM の変更が必要になるのはコードの保守性を大幅に低下させます。

同書籍では、CSS flex の仕様をまとめていた Google の Tab Atkins からの言葉として以下の引用も行っています。

chapter 2 の 3「フローレイアウトとフレックスボックスでは不十分だったレイアウト制御」より

CSS For Real Pages and Apps with Flexbox, Tab Atkins 15:00 くらい
フレックスボックスは非常にシンプルなページレイアウトには適していますが、より複雑なレイアウトには適していません。複雑な 2 次元のレイアウトには、テーブルレイアウトを彷彿とさせる酷い構造のネストされたフレックスボックスがたくさん必要になります。

2. CSS グリッドレイアウト デザインブック エビスコム著、マイナビ出版、2018 年

こちらは同じ著者の別の書籍です。

STEP 1 の 3「完成見本を CSS グリッドなしで作成する場合の問題点」より

そのために <div> を追加していますが、 これが原因で一部のリーダー機能(iOS / macOS Safari、 Edge、Mercury Reader など)では制作者が期待する形 でコンテンツが抽出されなくなります。⋯(中略)⋯ さらに、レスポンシブで一弾組にしたときのパーツの並び順も変わり、完成見本と異なるものになります。これも解決しようとすると、なかなかの力技が必要になります。

ネストした<div>は必ずしも悪ではない

たしかに不要な<div>のネストならば避けたほうがいいですが、「ネストした<div>は極力避けるべき」「<div>のネストは少なければ少ないほど良い」というのは行き過ぎです。むしろ<div>をネストさせたほうが見やすくなる、メリットがある場合もあります。

CSS grid で無理にネストを避けるよりも、積極的に<div>をネストさせることでメリットが実現できる例を2つ見てみましょう。

ツールバーの例

画像のようなツールバーのレイアウトを CSS grid で実現してみます。CSS grid ではcolumn-gapプロパティは grid コンテナ 1 つにつき 1 種類しか指定できないので、要素間の間隔が不均一なレイアウトはcolumn-gapでは実現できません。

このような場合、CSS grid ではcolumn-gapではなく幅の異なるトラックを用意してレイアウトを実現することがあります。

display: grid;
/* 幅の異なるトラックで、要素も間隔も両方定義する */
grid-template-columns: auto 14px auto 6px auto 6px auto 14px auto 4px auto;
/* column-gapは使わない */
padding-left: 6px;
padding-right: 6px;

これはこれで全く問題ない、よく使われるレイアウトなのですが、あえてこれを<div>のネストを使って実現してみましょう。<div>に合わせて CSS grid もネストさせることで、それぞれの<div>、CSS grid コンテナでは要素間の間隔が揃っています。

つまり、column-gapによって間隔を指定するという本来の使い方ができるようになりました。上画像で緑色になっている部分がcolumn-gapで指定できる間隔です。

React を使う場合は、ネストした<div>(CSS grid コンテナ)ごとにコンポーネントを分けることで、それぞれのコンポーネント内ではそれぞれの CSS grid コンテナにのみ集中でき、関心事の分離が可能になります。あらゆる場面でこのようにネストさせた上でコンポーネントを分割するべきとは言いませんが、場合によってはネストさせた<div>とコンポーネント分割を組み合わせるとわかりやすくなるでしょう。

カードレイアウトにおけるレイアウト分割の例

次にカードレイアウトの例です。下画像の様な単純なレイアウトであれば、ネストしない<div>と CSS grid でレイアウトを実現できます。

しかし、カード上の要素が増えてきて、うまく格子状に区切れなくなってくるとネストしない<div>と CSS grid だけではレイアウトが実現しづらくなってきます。

こういった場合は無理せず、<div>と CSS grid をネストさせて、ネストさせた先の子側の CSS grid でレイアウトを制御し、それを並べることで親側の CSS grid を構成すると所望のレイアウトを実現しやすくなります。

まとめ: <div>をネストする・しないは選択肢

本記事では CSS grid を使う上で、<div>をネストした方が所望のレイアウトを実現しやすくなる場合にも触れつつ、<div>のネストは忌避しなくてもよいことを説明してきました。

本記事の冒頭でも述べた通り、「ネストした<div>を極力避けなければならない」と思いこむことによって、単純に<div>をネストすれば楽な書けるのに、無駄に苦労することは避けていただきたいと私は思っています。

もちろん、<div>のネストをしない方が良い場合もあり、ネストがない方がスッキリして見やすい場合、あるいは一部のレスポンシブレイアウトでは注意深く<div>のネストを避けなければならないこともあるでしょう。

そういった場合は<div>のネストを後から取り除くことも出来るので、後のことは心配しすぎずに「必要と思ったら気軽に<div>をネストする」「後から不都合が出てきたらネストを解消する」くらいの姿勢のほうが HTML と CSS を書くスピードも上がってくる気がします。片方を常に忌避するのではなく、両方を選択肢としていつでも乗り換えられるようにしましょう。

GitHubで編集を提案

Discussion

HikaruooHikaruoo

突然のコメント失礼します。CSS Gridを使い始めた頃、私もHTMLをシンプルにしようと極端にネストを避けようとした経験がありますが、必要な場合にネストすることで柔軟で管理しやすいレイアウトが実現できる場面も多いですよね。特にReactのようなフレームワークを使うと、コンポーネント単位で分割できて関心ごとが明確になる点も納得です。最近は、自分のAPIテストツール EchoAPI を使って、ネストした要素や複雑なレイアウトでのAPI呼び出しも試しているのですが、コードが読みやすくなると確認作業もスムーズに進んで助かっています。貴重な視点をありがとうございます!