CSS Gridサブグリッド入門 第1回 サブグリッドの基本と使用例

CSS Gridの待望の機能、サブグリッドが主要なブラウザでサポートされました。基本的な使い方を見てみましょう。カードレイアウトの例を通じて、その強力なレイアウト能力について理解を深めます。

発行

著者 坂巻 翔大郎 フロントエンド・エンジニア
CSS Gridサブグリッド入門 シリーズの記事一覧

はじめに

CodeGridでは、これまでCSS Gridについての記事を数多く扱ってきました。今回の記事では、CSS Gridの機能である「サブグリッド」に焦点を当て、その基本的な使い方と使用例を紹介します。

サブグリッドは、CSS Grid Layout Module Level 2で導入された機能です。2023年には主要なブラウザでのサポートが実現しました。サブグリッドの登場により、CSS Gridの柔軟性と機能性はさらに高まりました。

サブグリッドについて理解するには、CSS Gridについての基本的な知識が必要です。もしCSS Gridの基本に不安がある場合は、次の記事を参照してください。

これらの記事では、CSS Gridの基礎から応用まで幅広くカバーしており、サブグリッドについて学ぶ上での良い基盤となるでしょう。

では、サブグリッドはどういうものなのか?具体的にどのように使用すればよいのか?このシリーズでは、サブグリッドの基本から始め、いくつかの具体的なレイアウト例を通じて、サブグリッドへの理解を深めていきます。

サブグリッドとは?

CSS Gridを使用する際に、グリッドの中にさらにグリッドを配置することがあります。通常、入れ子になっているグリッドの列や行は独立しています。ですので、親のグリッドの列や行のサイズを子のグリッドが参照することはできません。端的に言えば、子は整列できても孫は整列できないということです。

しかし、新たに登場した「サブグリッド」では、入れ子になったグリッドをサブグリッド化することにより、親のグリッドコンテナの列や行のサイズを参照できます。つまり、孫やそのまた孫までもが、親のグリッドの列や行に沿って整列できるのです。

サブグリッドを使うためには、入れ子になったグリッドに対して、grid-template-columnsgrid-template-rowsの値にsubgridを指定するだけです。

サブグリッドの基本的な使い方

まずは、サブグリッドを利用するための基本的なコード構造を見ていきましょう。

サブグリッドを使うと、グリッドコンテナ内のアイテムが、その親グリッドの行や列のサイズに直接合わせることができます。これは、入れ子になったグリッド構造で一貫した配置を保ちたい場合に特に便利です。

この図は、サブグリッドのイメージです。親グリッドコンテナは青い点線で、これに沿って配置されるサブグリッドが赤い点線で示されています。サブグリッド内の子は、青い点線の親グリッドに沿って整列しています。

こういった、親のグリッドに子側の子が整列するというのは、これまでのCSSではどう難しかったのでしょうか。まずはサブグリッドを使わずに、レイアウトを作成してみましょう。

<div class="grid-container">
  <div class="grid-item">1</div>
  <div class="grid-item">2</div>
  <div class="grid-item">3</div>
  <div class="grid-item no-subgrid">
    <div class="no-subgrid-item">4</div>
    <div class="no-subgrid-item">5</div>
    <div class="no-subgrid-item">6</div>
  </div>
</div>
/* 親:グリッドコンテナ */
.grid-container {
  display: grid;
  grid-template-columns: 50px 150px 200px;
  gap: 10px;
  width: 420px;
}
/* 子:グリッドアイテムかつグリッドコンテナ(擬似的なサブグリッド) */
.grid-item.no-subgrid {
  display: grid;
  grid-column: span 3;
  gap: 10px;
  grid-template-columns: 37px 150px 187px;
}

親のグリッドコンテナでは、3列のグリッドを作成し、その中に4つのグリッドアイテムを配置しています。4つ目のグリッドアイテムは、さらに3つのグリッドアイテムを持っています。

その4つ目のグリッドアイテムではgrid-column: span 3;とし、親のグリッドコンテナの3列分を占めています。そのうえで、3列を確保し、それぞれの列の幅をgrid-template-columns: 37px 150px 187px;のように指定します。さらに、アイテム間の間隔もgap: 10px;と親のグリッドコンテナと同じ値を指定しています。

このままでも、親のグリッドコンテナの列に沿って配置されているようにみえます。しかし、あくまで、親のグリッドコンテナの列の幅に合うように調整した列を新たに作っているだけで、親のグリッドコンテナの列をそのまま利用しているわけありません。もし、親のグリッドコンテナの列の幅が変わってしまったり、px単位ではないものを使いたい場合は、この方法ではうまくいかないこともあります。

そこで、サブグリッドを使うと、シンプルに書くことができます。

<div class="grid-container">
  <div class="grid-item">1</div>
  <div class="grid-item">2</div>
  <div class="grid-item">3</div>
  <div class="grid-item subgrid">
    <div class="subgrid-item">4</div>
    <div class="subgrid-item">5</div>
    <div class="subgrid-item">6</div>
  </div>
</div>

HTMLは先ほどと同じものですが、わかりやすさのためにclass名をno-subgridからsubgridと変更しています。CSSは次のようになります。

/* 子:グリッドアイテムかつグリッドコンテナ(サブグリッド) */
.grid-item.subgrid {
  display: grid;
  grid-column: span 3;
  grid-template-columns: subgrid;
}

サブグリッドを利用するための手順は簡単です。まず、サブグリッドを使いたいグリッドアイテムにdisplay: grid;を指定しグリッドコンテナとします。次に、grid-column: span 3;とし、親のグリッドコンテナの列を3列分を利用できるようにします。そして、grid-template-columns: subgrid;で、親のグリッドコンテナの列をサブグリッド内の列として利用できるようにします。

これで、親のグリッドコンテナの3列分をサブグリッド内で利用できるようになりました。

サブグリッド内のアイテムが、親グリッドの列に沿って配置されているのがわかります。.grid-item.subgridではアイテム間の余白(gap)の指定は行っていませんが、アイテム間は10px空いています。それは親のグリッドコンテナのgap: 10px;が引き継がれているためです。

使い方自体はいたってシンプルですが、実際にどう使えば良いのかがイメージしづらいと思います。ですので、具体的なレイアウト例と合わせて、サブグリッドの使い方を見ていきましょう。

カードレイアウトでのサブグリッドの使用例

次の画像のような、カードレイアウトをサブグリッドで指定してみましょう。カードレイアウトとは、カードと呼ばれる矩形の中に画像や見出し等のテキストがあるものを並べたレイアウトを指します。

こういったレイアウトでは、カード同士の高さやテキストの始まりの位置を揃えることが求められることがあります。

カード同士の高さを揃えることは、CSS GridやFlexboxを使うことで実現できます。ですが、それぞれのカード内のテキストの始まりの位置を他のカードと揃えることは、これまでCSS GridやFlexboxだけ*では難しかった部分でした。

* CSS GridやFlexboxだけでは難しかった

CSS GridやFlexboxを使う場合、テキストの位置を揃えるにはCSSのみでは難しいため、JavaScriptを使用します。端的に説明すると、同じ高さにしたい要素らの高さを取得したのち、一番高いものの高さに揃えるというものです。

サブグリッドでカードレイアウトを実装する

今回解説する、サブグリッドを使うことで、カード同士の中身の位置を行内で揃えられるようになります。

では、カードレイアウトの基本的な構造を見ていきましょう。HTMLは特筆することはありません。

カードレイアウトのHTML

<ul class="CardList">
  <!-- カード -->
  <li class="CardList_Item">
    <img class="CardList_Img" src="card-image.png" alt="">
    <h2 class="CardList_Title">タイトル1</h2>
    <p class="CardList_Description">タイトル1の概要</p>
    <a class="CardList_Link" href="#">「タイトル1」詳細へ</a>
  </li>
  <!-- カード -->
  <li class="CardList_Item">
    <img class="CardList_Img" src="card-image.png" alt="">
    <h2 class="CardList_Title">タイトル2タイトル2タイトル2</h2>
    <p class="CardList_Description">タイトル2の概要</p>
    <a class="CardList_Link" href="#">「タイトル2」詳細へ</a>
  </li>
  <!-- 省略 -->
</ul>

まず、サブグリッドを使わないCSSから見ていきましょう。カードの並べ方としては、auto-fitを利用して、幅に応じて列数が変化するようになっています。.CardList_Item内には、画像、見出し、概要、詳細へのリンクが縦に並んでいます。

サブグリッドを使わない場合のCSS

.CardList {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 30px;
  list-style: none;
  padding: 0;
}
.CardList_Item {
  padding: 20px;
  border: 1px solid #ccc;
}

デモを見てわかる通り、カードが並んでいるものの、それぞれのカード内のテキストの始まりの位置がばらばらで、他のカードと揃っていません。これをサブグリッドを使って解決します。まずはサブグリッドを使用したデモをみてみましょう。

それぞれのカード内のテキストの始まりの位置が揃っています。タイトルや概要が長くなった場合でも、親グリッドコンテナの行に沿って配置されているため、それぞれの位置が揃っています。CSSは次のようになっており、.CardList_Itemをサブグリッドにしています。

サブグリッドを使う場合のCSS

.CardList_Item {
  padding: 20px;
  border: 1px solid #ccc;

  /* 追加 */
  display: grid;
  grid-template-rows: subgrid;
  grid-row: span 4;
  gap: 10px
}

追加したコードについて見ていきましょう。

まずdisplay: grid;grid-template-rows: subgrid;を使うことで、サブグリッドとなります。

次にgrid-row: span 4;は、.CardList_Itemが親(.CardList)のトラック4行にまたがるようになります。これによってサブグリッドは親のグリッドを4行分利用できるようになります。

そして、行の間隔は親から継承されるため30pxとなるところを、gap: 10px;とし、サブグリッド内の行の間隔を10pxに上書きしています。

サブグリッドを使う上での注意点

注意する点としては、サブグリッドのカード内で利用する行数は決まっている必要があることです。確保した4行よりも多い行数が使われる場合でも、サブグリッド内では新しい行(5行目)が作られることはありません。

1つ目のカード内の要素を5つに変更したデモを見てみましょう。

「タイトル1の補足」という要素を追加していますが、「「タイトル1」詳細へ」のリンクと重なっています。4行分しか確保しておらず、暗黙のグリッドが作成されません。行き場がなくなった要素は、最後の行(4行目)に配置されてしまいます。

通常、サブグリッドでない場合に、行や列の個数が決まっていなくても個数に合わせて暗黙のグリッドが作成されるため、このような問題は発生しません。しかし、サブグリッド内では暗黙のグリッドが作成されないため、行や列の個数が決まっている必要があるという点に注意してください。

ここまでのまとめ

サブグリッドは、親グリッドの行や列をサブグリッド内で利用できるようにする機能です。サブグリッドは、グリッドアイテムに対して、display: grid;grid-template-columns: subgrid;grid-template-rows: subgrid;を指定して利用します。

サブグリッドを使うことで、カードレイアウトを実装する際に、カード同士のカード内のテキストの始まりの位置を揃えることができるようになりました。ただし、サブグリッド内では暗黙のグリッドが作成されないため、行や列の個数が決まっている必要があります。

次回は、実務で頻出するようなレイアウト例を通じて、サブグリッドへの理解をさらに深めていきます。