HTML / CSSのレイアウト革命!display:gridの使い方を理解してスマートにコーディングしよう!

HTMLの横並びの歴史をたどると、float: leftが主流の時代から、display: flexが主流の時代となり、そして、新しくdisplay: gridの時代が到来しようとしています。

大げさに革命という言葉を使いましたが、何が凄いかと言うと、

  • 記述用が圧倒的に少なくなる点
  • 配置場所の転換が非常に簡単になる点

の2つですね。

とにかくその利便性から、おそらく今後の主流はdisplay: gridになってくると思うので、まだあまり理解できていない方はぜひ押さえておきましょう!

目次

display: gridの考え方の基本

gridは横に○列、縦に○行といった立体的な指定をします。図は横3列 ✕ 縦3行の例ですが、こんな感じでエリアを作ってアイテムを配置していくような形がdisplay:grid;の基本です。

area1には、このアイテム、area2には、このアイテムといった形で埋めていきます。あるいは、area1とarea2に、このアイテムといった形で複数のエリアを選択して埋めていくことも可能ですし、複数のエリアを選択する際には、area1、area2、area4、area5のアイテムと、area5、area6、area8、area9のようにarea5が被っていても重ねて表示させることも可能だったりします。

上記の図のような表現は以下のコードでおおむね再現可能です。
※ コードの意味は以降で紹介していくので今は深く考えなくても大丈夫です!

.grid {
	display: grid;
	grid-template-columns: 1fr 1fr 1fr;
	grid-template-rows: 100px 100px 100px;
}
<div class="grid">
  <div class="grid__item">Grid1</div>
  <div class="grid__item">Grid2</div>
  <div class="grid__item">Grid3</div>
  <div class="grid__item">Grid4</div>
  <div class="grid__item">Grid5</div>
  <div class="grid__item">Grid6</div>
  <div class="grid__item">Grid7</div>
  <div class="grid__item">Grid8</div>
  <div class="grid__item">Grid9</div>
</div>

display: gridの書き方の基本

基本は親要素にdisplay: grid;を指定するだけです。
.grid__itemはエリアを分かりやすくするために色分けしています。

.grid {
	display: grid;
}
<div class="grid">
  <div class="grid__item">Grid1</div>
  <div class="grid__item">Grid2</div>
  <div class="grid__item">Grid3</div>
  <div class="grid__item">Grid4</div>
  <div class="grid__item">Grid5</div>
  <div class="grid__item">Grid6</div>
  <div class="grid__item">Grid7</div>
  <div class="grid__item">Grid8</div>
  <div class="grid__item">Grid9</div>
</div>

デベロッパーツールを見ても、girdとして認識されていることが分かります。

ちなみに最近のChromeデベロッパーツールは、グリッドレイアウトのCSSプロパティを認識して操作しやすくしてくれているので、ぜひ活用してみてください!

行と列の枠を指定する

最初の図で見たとおりgridの特徴して、枠をあらかじめ用意しておくといったものがあります。○列 ✕ ○行という枠組みをあらかじめ決めておくことが基本となります。

行と列の枠の指定の仕方ですが、

  • 列はgrid-template-columns
  • 行はgrid-template-rows

で指定します。display: grid;と同じ要素に指定します。

今回は3列3行ということで指定しようと思います。

.grid {
	display: grid;
	grid-template-columns: 300px 300px 300px;
	grid-template-rows: 150px 150px 150px;
}
<div class="grid">
  <div class="grid__item">Grid1</div>
  <div class="grid__item">Grid2</div>
  <div class="grid__item">Grid3</div>
  <div class="grid__item">Grid4</div>
  <div class="grid__item">Grid5</div>
  <div class="grid__item">Grid6</div>
  <div class="grid__item">Grid7</div>
  <div class="grid__item">Grid8</div>
  <div class="grid__item">Grid9</div>
</div>

grid-template-columnsgrid-template-rowsも指定の仕方は同様ですが、columnsであれば、左から順番にエリアが確保されていき、rowsであれば上から順番にエリアが確保されていきます。以下の図のような幅と高さが子要素に適応されるような形ですね。

新しい単位「fr」

gridにはfrという聞き慣れない単位が使われます。fractionの略のようです。

イメージとしては、table-layout: fixed;というtableを等分にするCSSプロパティに近い感覚です。gridを指定した要素の未指定の幅をfrの数で割った分の幅が1frで確保されます。

例えば、以下のように1frで3列作ると3等分になるということですね。

.grid {
	display: grid;
	grid-template-columns: 1fr 1fr 1fr;
}
<div class="grid">
  <div class="grid__item">Grid1</div>
  <div class="grid__item">Grid2</div>
  <div class="grid__item">Grid3</div>
  <div class="grid__item">Grid4</div>
  <div class="grid__item">Grid5</div>
  <div class="grid__item">Grid6</div>
  <div class="grid__item">Grid7</div>
  <div class="grid__item">Grid8</div>
  <div class="grid__item">Grid9</div>
</div>

では、固定値とfrが混ざるとどうなるでしょうか?これは、固定値を引いたあとの幅からfrの数で割った幅が1frとして認識されます。ここがtable-layout: fixedと似ているなって思ったりします。

テーブルのCSSに関しては以下の記事でもまとめているのでtable-layout: fixedが分からない方は「テーブルの列を全て均等にする」を参考にしてください!

例えば、最後の列を600pxで指定すると、600pxを除いた幅から、(frが2つなので)2等分して表現してくれます。

.grid {
	display: grid;
	grid-template-columns: 1fr 1fr 600px;
	grid-template-rows: 150px 150px 150px;
	background: #eee;
}
<div class="grid">
  <div class="grid__item">Grid1</div>
  <div class="grid__item">Grid2</div>
  <div class="grid__item">Grid3</div>
  <div class="grid__item">Grid4</div>
  <div class="grid__item">Grid5</div>
  <div class="grid__item">Grid6</div>
  <div class="grid__item">Grid7</div>
  <div class="grid__item">Grid8</div>
  <div class="grid__item">Grid9</div>
</div>

繰り返しで指定できる

先ほど3等分するときにgrid-template-columns: 1fr 1fr 1fr;といった形で1frを3回書きましたが、repat()というCSS関数を使うことで効率的に記載することが可能です。

grid-template-columns: repeat(3, 1fr);のような書き方をします。

.grid {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	grid-template-rows: 150px 150px 150px;
	background: #eee;
}

repeat関数の変数として、繰り返す回数を左側に、繰り返す値を右側に書いてあげればOKです。

<div class="grid">
  <div class="grid__item">Grid1</div>
  <div class="grid__item">Grid2</div>
  <div class="grid__item">Grid3</div>
  <div class="grid__item">Grid4</div>
  <div class="grid__item">Grid5</div>
  <div class="grid__item">Grid6</div>
  <div class="grid__item">Grid7</div>
  <div class="grid__item">Grid8</div>
  <div class="grid__item">Grid9</div>
</div>

配置は自由自在

girdの特徴は、用意したエリアに対して、子要素を自在に配置変換が可能という点です。スマホでは縦並びだけど、PCの時は、下のコンテンツを左上に配置するみたいな、かつては2重のコードで表現する必要があったことも実にシンプルなコードで実現できてしまいます。

<div class="grid">
  <div class="grid__item">Grid1</div>
  <div class="grid__item">Grid2</div>
  <div class="grid__item">Grid3</div>
  <div class="grid__item">Grid4</div>
  <div class="grid__item">Grid5</div>
  <div class="grid__item">Grid6</div>
  <div class="grid__item">Grid7</div>
  <div class="grid__item">Grid8</div>
  <div class="grid__item">Grid9</div>
</div>

かなり自由に位置を変更してみました。用意したエリアのどこに配置するかは、grid-columngrid-rowを子要素に指定することで変更できるようになります。

.grid__item:nth-child(1) {
	background: #f8bbd0;
  grid-column: 1 / 2;
  grid-row: 2 / 3;
}

.grid__item:nth-child(2) {
	background: #d1c4e9;
  grid-column: 2 / 3;
  grid-row: 2 / 3;
}

.grid__item:nth-child(3) {
	background: #bbdefb;
  grid-column: 2 / 3;
  grid-row: 1 / 2;
}

.grid__item:nth-child(4) {
	background: #b2ebf2;
  grid-column: 3 / 4;
  grid-row: 1 / 2;
}

.grid__item:nth-child(5) {
	background: #e6ee9c;
  grid-column: 1 / 2;
  grid-row: 1 / 2;
}

.grid__item:nth-child(6) {
	background: #DCEDC8;
  grid-column: 3 / 4;
  grid-row: 3 / 4;
}

.grid__item:nth-child(7) {
	background: #FFF9C4;
  grid-column: 2 / 3;
  grid-row: 3 / 4;
}

.grid__item:nth-child(8) {
	background: #FFCCBC;
  grid-column: 1 / 2;
  grid-row: 3 / 4;
}

.grid__item:nth-child(9) {
	background: #F8BBD0;
  grid-column: 3 / 4;
  grid-row: 2 / 3;
}

書き方のルールとしては、スタート地点とゴール地点を指定する形です。スラッシュという記号がややこしいですが、これは〇〇から〇〇という範囲を表す役割だと脳内変換してもらえたらと思います。

ちょっと分かりづらいので図にしました。gridで作成された領域には、こんな感じで番号が振られるようなイメージです。

grid-column: 1 / 2;とは、1から2の列を指しており、grid-row: 1 / 2;とは、1から2の行を指しているということです。1から2の列と1から2の行のエリアということで、左上のエリアに配置されるということですね。

ちなみに、この番号が振られた線のことをグリッドラインと呼んだりします。

余白はgapで

gridの余白がgapで簡単に設定することができます。使い方としては、列の余白はcolumn-gapで指定して、行の余白はrow-gapで指定します。

.grid {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	grid-template-rows: 100px 200px;
	column-gap: 30px;
	row-gap: 30px;
	background: #eee;
}
<div class="grid">
  <div class="grid__item">Grid1</div>
  <div class="grid__item">Grid2</div>
  <div class="grid__item">Grid3</div>
  <div class="grid__item">Grid4</div>
  <div class="grid__item">Grid5</div>
  <div class="grid__item">Grid6</div>
  <div class="grid__item">Grid7</div>
  <div class="grid__item">Grid8</div>
  <div class="grid__item">Grid9</div>
</div>

また、列と行のgapはまとめて書くことができまして、gapとしてgap: 30px 30px;や列と行が同じ値の場合はgap: 30px;といった書き方も可能です。

display: flexでの表現をdisplay: gridでやってみる

flexboxでもやっていたような基本的な表現をgridで作ってみようと思います。

カード一覧

これまで紹介しているコードとほぼ同じですが、gridを使うと余白の定義も簡単ですし、幅を1frで等倍にすることで簡単に横並びで等倍のカード一覧を作ることが可能です。

<div class="grid">
  <div class="grid__item card1">Card1</div>
  <div class="grid__item card2">Card2</div>
  <div class="grid__item card3">Card3</div>
  <div class="grid__item card4">Card4</div>
  <div class="grid__item card5">Card5</div>
</div>

カードの枚数を自動で増減

先ほどの例だとカードは常に3列をキープしたままだと思います。gridでは新しいminmaxという関数と、すでに紹介したrepeat関数、そして、repeat関数の中でも繰り返す回数としてauto-fitを指定することで、かなり柔軟な横並び枚数の調整ができるようになりました!

列の指定に対して、repeat(auto-fit, minmax(300px, 1fr));のような書き方になります。
※ 300pxは最低限維持したカードの幅。

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 30px;
}
<div class="grid">
  <div class="grid__item card1">Card1</div>
  <div class="grid__item card2">Card2</div>
  <div class="grid__item card3">Card3</div>
  <div class="grid__item card4">Card4</div>
  <div class="grid__item card5">Card5</div>
</div>

親の幅に対して、入るだけ300pxのカードを入れてくれます。余った余白に関しては、均等に300pxに加えて増やしてくれるような動きですね。入り切らなかった分は次の行に入ります。

要するに、次の動画のように幅に応じて勝手に列数を変えてくれるといった動きになります。

Webサイトのレイアウト

ヘッダー、2カラムのメインコンテンツ(メインとサイドバー)、フッターといったよくあるWebサイトの構成もgridで簡単に再現できます。

headerfooterdivで囲む必要があるのが、ちょっと嫌な感じはしますが…。bodyでやるのもなんか違和感…

<div class="grid">
  <header class="grid__header">ヘッダー</header>
  <main class="grid__main">メイン</main>
  <aside class="grid__side">サイド</aside>
  <footer class="grid__footer">フッター</footer>
</div>

子要素の上下中央揃え

gridalign-contentjustify-contentの3行で上下左右の中央揃えが可能です。

<div class="grid">文字</div>

幅のない横並び

あらかじめ幅の決まっていない横並びもあると思います。パンくずやユーティリティメニューのような文字のサイズに応じて横並びしたいようなパターンですね。

こちらも対応は可能です。ただし、改行したい場合は、flexboxのほうがいいかもしれません。。

対応方法として具体的にはjustify-content:start;を指定することで可能となります。もともとjustify-content: stratch;が適応されているのですが、これが親要素の幅いっぱいにならなくなります。

また、並びをgrid-auto-flow: column;として、変えてあげます。

<div class="float">
  <div class="float__item">アイテム1</div>
  <div class="float__item">アイテム2</div>
  <div class="float__item">アイテム3</div>
  <div class="float__item">アイテム4</div>
  <div class="float__item">アイテム5</div>
</div>

横並びでもFlexboxで書いたほうが良さそうなパーツ

gridが主流になってもFlexboxで書きそうなパーツです。おそらく、よしなに改行してほしいみたいな並びはFlexboxになるのかと思います。

例えば、以下のような横並びのユーティリティメニューなど。

<div class="wrap">
<div class="flexbox">
  <div class="flexbox__item"><a href="">Grid1</a></div>
  <div class="flexbox__item"><a href="">Grid2</a></div>
  <div class="flexbox__item"><a href="">Grid3</a></div>
  <div class="flexbox__item"><a href="">Grid4</a></div>
  <div class="flexbox__item"><a href="">Grid5</a></div>
  <div class="flexbox__item"><a href="">Grid6</a></div>
  <div class="flexbox__item"><a href="">Grid7</a></div>
  <div class="flexbox__item"><a href="">Grid8</a></div>
  <div class="flexbox__item"><a href="">Grid9</a></div>
  <div class="flexbox__item"><a href="">Grid10</a></div>
</div>
</div>

1次元レイアウトがFlexbox、2次元レイアウトがGridという説明をされていることが多いように思います。単純な1次元の横並びのレイアウトの場合は、Flexboxを検討するといいのかもしれません。

位置関係のプロパティの整理

この記事ではあまり登場していませんが、、、位置に関するプロパティがたくさんあるので整理しておきましょう(使う必要が出てきたときに、この章を見返してもらえらと思います)

親要素内のでの位置の調整

display:grid;のエリアに対して、各子アイテムをどういった位置関係で並べるかを決めるためのプロパティとなります。他の子アイテムを意識しながら決めていくのがポイントですね。

  • justify-content・・・横の位置をどう揃えるか
  • align-content・・・縦の位置をどう揃えるか

display:grid;は何もしなければ親要素のエリアいっぱいを使ってスペースを埋めるような動きをします。上記のプロパティで位置を指定することで、自動でスペースを使う機能を解除して、列や行の配置関係を決めることが可能です。

子アイテムの位置

子アイテムが用意されたエリアの中で、どの位置に配置するかを決めるものです。こちらは、他の子アイテムのことは意識せずに自分のエリアの中だけで考えます。

  • justify-items・・・左右の位置関係
  • align-items・・・上下の位置関係

おわり

gridに関する初歩的な概念と使い方でした!gridを使うことで

  • 記述用が圧倒的に少なくなる点
  • 配置場所の転換が非常に簡単になる点

の大きなメリットを受けることができます。CSSの各プロパティには状況に応じた使い方があって、全てが全てgridになるわけではないと思いますが、便利なプロパティであることは間違いないので、まだ慣れていない人はぜひ少しずつ使ってみてください!

この記事が気に入ったら
フォローしてね!

この記事を書いた人

WordPressが得意なWeb屋。HPcode代表。

300件以上のWordPressカスタマイズを対応してきました。SE → 農家 → アフィリエイター → Web屋。生まれは三重県。

目次