CSSグリッド入門 - 図解でわかりやすく解説

174
210

CSSのGrid Layoutグリッド・レイアウトとは、ウェブサイトのレイアウトを構築するための仕様です。昔はウェブサイトのレイアウトを実現するために、floatやFlexboxを使っていた方が多いのではないでしょうか。

Grid Layoutを使えば、HTML要素の構造を汚さず、従来の手法に比べてウェブサイトのレイアウトがつくりやすくなります。とくに、Flexboxではつくるのが難しい、縦軸・横軸がある格子状のレイアウトに向いています。

今回はレイアウトをつくりながら、Grid Layoutの基礎知識について紹介します。余裕のある方は、記事を読みながら実際に手を動かしてレイアウトをつくってみましょう。

この記事で学べること

  • Grid Layoutの基本的な使い方
  • Grid Layoutの利点
  • サブグリッドの使い方
  • grid-templateプロパティのアニメーション

よくあるレイアウトをつくりながらGrid Layoutの基礎を学ぶ

次のようなヘッダー・メインコンテンツ・左右のサイドバー・フッターがあるレイアウトを例に解説します。

<div class="container">
  <header class="header">header</header>
  <main   class="main"  >main</main>
  <aside  class="aside" >aside</aside>
  <nav    class="nav"   >nav</nav>
  <footer class="footer">footer</footer>
</div>

まずHTMLを書きます。配置する各要素と、それを囲む親要素があります。親要素にはcontainer というクラス名を付けました。

Flexboxで作る場合は

Flexboxを使ってこのレイアウトをつくる場合、横ならびにしたい要素(asidemainnav)をdivタグなどで囲んでフレックスコンテナーをつくり、横ならびにする要素をフレックスアイテムとして配置します。

わざわざdivタグを追加する必要があるため、余計な要素が1つ増えますよね。

Grid Layoutで作る場合は

Grid Layoutはレイアウトを囲むコンテナーの要素(例では.containerにその子要素の配置の仕方を指定します。Flexboxと違い、要素を並べる行・列コンテナーとなる要素を用意する必要はありません

Grid Layoutのコンテナーとアイテムについて説明しながらCSSでレイアウトをつくっていきます。

グリッドコンテナー

グリッドレイアウトで要素を配置するためにグリッドコンテナーをつくります。要素に display: grid を指定すると、その要素はグリッドコンテナーになります。(インライン要素として扱うときはdisplay: inline-gridを指定します)

.container {
  display: grid;
}

これだけではまだ要素がただ並んでいるだけです。そこで、グリッドコンテナーにグリッドコンテナーを分割するための指定をします。

グリッドコンテナーを縦・横に分割します。縦方向に分割した各列のサイズはgrid-template-columns 、横方向に分割した各行のサイズはgrid-template-rows で指定します。

列の幅を指定しましょう。今回のレイアウトでは、左のサイドバーの幅が180px、右のサイドバーの幅が160pxです。中央のメインエリアは親要素の幅から左右のサイドバーの幅を引いた可変幅にします。

ここで、メインエリアの幅指定にfrという単位を使います。frはグリッドコンテナーの中を分割するサイズの指定に使える単位です。全体の幅からfr以外の単位(px%など)で指定したものを引き、残りの幅がfrで指定された列に配分されます。Flexboxのflex-growプロパティと同じようなイメージです。今回は、全体の幅から左右サイドバー(180px、160px)の幅を引いた幅をメインエリアに配分したいので次のように書きます。

.container {
  display: grid;
  /* 1列目から順番に180px、1fr、160pxの幅 */
  grid-template-columns: 180px 1fr 160px;
}

同じように各行の高さも指定します。

.container {
  display: grid;
  /* 1列目から順番に180px、1fr、160pxの幅 */
  grid-template-columns: 180px 1fr 160px;
  /* 1行目から順番に60px 1fr 90pxの高さ */
  grid-template-rows: 60px 1fr 90px;
}

このときの列・行のことをグリッドトラックといいます。列・行を分割した線をグリッドラインといいます。グリッドラインは、borderのように見た目上の線ではありません。

グリッドアイテム

グリッドアイテムを配置します。グリッドコンテナー直下の子要素をグリッドアイテムといいます。今回の場合は、ヘッダー・メインコンテンツ・左右のサイドバー・フッターがグリッドアイテムです。

グリッドトラックを分割したグリッドラインは、1本目から順番に1,2,3…と自動的に番号がふられます。grid-column-startgrid-column-endで、グリッドアイテムが列の何本目から何本目のグリッドラインまで配置するか指定します

同じようにgrid-row-startgrid-row-endで行の何本目から何本目のグリッドラインまで配置するか指定します。

.header {
  /* 列の1本目から4本目のグリッドラインまで */
  grid-column-start: 1;
  grid-column-end: 4;
  /* 行の1本目から2本目のグリッドラインまで */
  grid-row-start: 1;
  grid-row-end: 2;
}

このとき、grid-column-endgrid-row-endautoを指定すると、それぞれgrid-column-startgrid-row-startで指定したグリッドラインの次のグリッドラインまでの範囲に配置されます。ヘッダーのgrid-row-endの指定はautoにできます。

.header {
  /* 列の1本目から4本目のグリッドラインまで */
  grid-column-start: 1;
  grid-column-end: 4;
  /* 行の1本目から2本目のグリッドラインまで */
  grid-row-start: 1;
  grid-row-end: auto;
}

同じように他のグリッドアイテムも配置します。

.header {
  /* 列の1本目から4本目のグリッドラインまで */
  grid-column-start: 1;
  grid-column-end: 4;
  /* 行の1本目から2本目のグリッドラインまで */
  grid-row-start: 1;
  grid-row-end: auto;
}

.main {
  /* 列の2本目から3本目のグリッドラインまで */
  grid-column-start: 2;
  grid-column-end: auto;
  /* 行の2本目から3本目のグリッドラインまで */
  grid-row-start: 2;
  grid-row-end: auto;
}

.aside {
  /* 列の1本目から2本目のグリッドラインまで */
  grid-column-start: 1;
  grid-column-end: auto;
  /* 行の2本目から3本目のグリッドラインまで */
  grid-row-start: 2;
  grid-row-end: auto;
}

.nav {
  /* 列の3本目から4本目のグリッドラインまで */
  grid-column-start: 3;
  grid-column-end: auto;
  /* 行の2本目から3本目のグリッドラインまで */
  grid-row-start: 2;
  grid-row-end: auto;
}

.footer {
  /* 列の1本目から4本目のグリッドラインまで */
  grid-column-start: 1;
  grid-column-end: 4;
  /* 行の3本目から4本目のグリッドラインまで */
  grid-row-start: 3;
  grid-row-end: auto;
}

grid-column-startgrid-column-endgrid-columngrid-row-startgrid-row-endgrid-rowという略式プロパティで指定できます。このとき、autoは省略できます。今回の .headerはこのように略式プロパティで書き換えることができます。

.header {
  /* 列の1本目から4本目のグリッドラインまで */
  grid-column: 1 / 4;
  /* 行の1本目から2本目のグリッドラインまで */
  grid-row: 1;
}

これでレイアウトは完成です。以下のサンプルでコードと表示を確認してみてください。

コラム: 1frでレイアウトが思った通りにならないとき

1frを指定しているのに思った通りにレイアウトできないことがあります。その場合は以下の記事を参考にするといいでしょう。

タイル状のレイアウトをGrid Layoutで

タイルが並ぶように同じ幅のアイテムが繰り返し配置されるレイアウトをGrid Layoutでつくってみます。

このようなレイアウトは、floatやFlexboxでもつくることができますがGrid Layoutを使うことで便利になったポイントを紹介します(今回紹介していないプロパティも使っています)。このサンプルでは、Grid Layoutに関するCSSはグリッドコンテナーのみに指定しており、少ないプロパティでこのレイアウトをつくることができました。

.container {
  /* グリッドコンテナ */
  display: grid;
  /* 最小100px、最大1frの列を繰り返しつくる */
  grid-template-columns: repeat(
    auto-fill,
    minmax(100px, 1fr)
  );
  column-gap: 10px;
  row-gap: 10px;
}

レイアウトに関する指定をグリッドコンテナーにまとめられる!

まず1つ目に、グリッドコンテナーの指定のみでこのレイアウトをつくれるのはとても便利です。floatやFlexboxでレイアウトするとき、親要素にコンテナーとなる指定をして、横ならびにするアイテムにはアイテムの幅や余白の指定をする必要があったと思います。Grid Layoutでは、グリッドコンテナーにグリッドアイテムの配置についての指定ができます。

アイテム間の余白調整が手軽

2つ目はrow(column)-gapでグリッドアイテム間の余白を指定していることです。row(column)-gapは、グリッドアイテムの間にだけ余白ができるようになっています。

floatやFlexboxでこのレイアウトをするには、余白の処理に工夫をする必要があります(例:marginをつけて、レイアウトの端等の不要なmarginをネガティブマージンやE:nth-child(n)で消す)。gapを使えば、そういった調整は必要はありません。

親要素が可変幅でもアイテムのサイズ調整がシンプル

3つ目はgrid-template-columns の値、repeat(auto-fill, minmax(100px, 1fr))です。これは、グリッドトラックのサイズの指定に使えるrepeat()auto-fillを使って親要素におさまるようにアイテムを繰り返し横ならびにし、minmaxでアイテムの最小幅・最大幅を指定しています。

floatやFlexboxの横並びレイアウトではレスポンシブ対応をするとき、表示の幅によって各列にいくつのアイテムが並ぶように、どんな幅にするかという指定を複数のプロパティでする必要がありました。Grid Layoutのrepeatauto-fillminmaxをうまく使うと、可変幅レイアウトの調整がしやすくなると思います。

サブグリッド

CSS Gridにはサブグリッドという機能があります。通常のCSS Gridだと直下の要素しかグリッドアイテムとして認識されません。Gridを親子でそれぞれ繰り返し指定すればグリッドの入れ子ができますが、親子のグリッドは連動しません。

サブグリッドを使うと、グリッドの入れ子ができ、親子のグリッドが連動します

具体的には以下の挙動を確認するとわかりやすいでしょう。

1カラム内には、サムネイル・タイトル・概要文・リンクを配置しています。それぞれのカラムでは文字量が異なりますが、サブグリッドの効用によって、高さが揃っていることが確認できます。

以下はサブグリッドの抜粋です。子要素にdisplay: grid;を指定したうえで、grid-template-rows: subgrid;を指定していることがポイントです。

.container {
  /* グリッドコンテナ */
  display: grid;
  /* 最小256px、最大1frの列を繰り返しつくる */
  grid-template-columns: repeat(auto-fill, minmax(256px, 1fr));
  /* 余白 */
  gap: 16px;
}

.item {
  display: grid;
  grid-row: span 4;
  grid-template-rows: subgrid; /* サブグリッド */
}

アニメーション

grid-template-columnsgrid-template-rowsgrid-templateプロパティ(一括指定)はアニメーション可能です。

以下の作例では、グリッドアイテムをホバーした際全体的に行の高さが広がり、ホバーしているアイテムだけ列の幅が拡大します。

:has()疑似クラスを使用し、グリッドアイテムがホバーされた時コンテナー側からグリッドサイズを変更しています。

参照:『has()疑似クラスでコーディングが変わる! CSS最新スタイリング

/* グリッドコンテナ */
.container {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr 1fr;
  grid-template-rows: 50px;
  transition: grid-template 0.8s ease;

  /* 列の幅を変更する */
  /* 5fr: ホバーされたアイテムは広めに(5/8エリア分) */
  /* 1fr: ホバーされたアイテム以外はサイズ変更しない */
  &:has(> .item:nth-of-type(1):hover){
    grid-template-columns: 5fr 1fr 1fr 1fr;
  }
  &:has(> .item:nth-of-type(2):hover){
    grid-template-columns: 1fr 5fr 1fr 1fr;
  }
  /* (3・4は省略) */

  /* 行の高さを変更する */
  &:has(> .item:hover){
    grid-template-rows: 280px;
  }

  /* ホバーされたアイテム以外は半透明で表示 */
  &:has(.item:hover) .item:not(:hover) {
    opacity: 0.5;
  }
}

/* グリッドアイテム */
.item{
  min-width: 60px;
  transition: opacity 0.8s;
}

※ CSSネスト記法を使用(Grid Layoutに関連する記載を抜粋)

うまくアニメーションさせるには単位を揃える必要があります

▼NG例

  • repeat(3, 1fr)2fr 1fr 1fr(列数や行数は同じだが、指定方法が異なるため値が補間されない)
  • 1fr 1fr 1fr2fr 1fr 1fr 1fr(異なる列数や行数)
  • 80px1fr(異なる単位)

▼OK例

  • 1fr 1fr 1fr2fr 1fr 1fr(グリッドのサイズを列挙して指定し、アニメーションさせたい部分だけ変更)
  • 80px200px(単位が揃っている)

各ブラウザの実装状況

Grid Layoutは2017年10月以降リリースのChrome、Firefox、Safari、Edge含む主要なブラウザで利用可能です。

サブグリッドはChrome 117・Edge 117(2023年9月)、Safari 16.0(2022年9月)、Firefox 71(2019年12月)以上で利用できます。

終わりに

今回はGrid Layoutの基本的なレイアウトの作り方と、プロパティを紹介しました。グリッドレイアウトで実現可能なことは他にもたくさんあります。

続編記事『特徴で使い分けたいCSSレイアウト手法』では、Grid LayoutとfloatとFlexboxとの違いについて紹介します。あわせてご覧くださいませ。

※この記事が公開されたのは7年前ですが、先月4月に内容をメンテナンスしています。

編集部

ICS MEDIAは株式会社ICSが運営するオウンドメディアです。ICSはインタラクションデザイン専門のプロダクション。最先端のウェブテクノロジーを駆使し、オンスクリーンメディアの表現分野で活動しています。

この担当の記事一覧