gridレイアウトについて調べました【CSS/grid-template/auto-fit/auto-fill】

css

最近CSSのgridを使う機会がありました。
最低限の仕組みを知っておく必要があると思い、基本的な並べ方を実装する方法をまとめました。

gridの基本的な使い方

gridは要素の表示形式を設定するdisplayプロパティの値になります。

displayプロパティにgridを指定すると、こんな風に要素をタイル状に並べることができます。

こういったレイアウトをグリッドレイアウト、タイル状にならんだ要素のことをここではセルと呼びます。
同じdisplayプロパティのflex、もしくはfloatプロパティでも同じことができますが、もっと簡潔にCSSを記述できます。

CodePenで実際の表示を確認できます。

See the Pen grid-sample1 by donguri2020 (@m-ke) on CodePen.

HTMLは次の通りです。クラス名wrapperの子要素にDIV要素があります。これがタイル状に並んでいます。

<div class="wrapper">
  <div>item1</div>
  <div>item2</div>
  <div>item3</div>
  <div>item4</div>
  <div>item5</div>
  <div>item6</div>
  <div>item7</div>
  <div>item8</div>
</div>

gridに関するCSSを抜き出したのがこちらです。
親要素wrapperにCSSを設定します。
これだけの記述でグリッドレイアウトが実装できます!

.wrapper {
  display: grid; // グリッドレイアウト
  grid-template-columns: repeat(3, 1fr); // 横に3つ並べる
  grid-template-rows: repeat(3, 100px); // 縦に3つ並べる
  gap: 10px; // 要素同士の余白を10pxにする
}

displayプロパティにgridを設定

まず、displayプロパティにgridを指定します。

display: grid;

これだけだとセルはタイル状に並びません。
セルのレイアウトに関する設定が必要です。

いくつセルを並べるか指定する

まず縦と横、それぞれ何個のセルを並べるか明示的に指定します。今回、縦横それぞれ3個のセルを並べることにします。

縦に何個並べるか grid-template-rows

grid-template-rowsに、セルの高さを指定します。
高さは、並べるセルの数だけ半角スペースで区切って設定します。
以下は高さが130px 、200px、100pxの要素を3つ並べたい場合です。

grid-template-rows: 130px 200px 100px;

横に何個並べるか grid-template-columns

grid-template-columnsに、セルの横幅を指定します。
横幅は、並べるセルの数だけ半角スペースで区切って設定します。
以下は横幅が100px 、200px、150pxの要素を3つ並べたい場合です。

grid-template-columns: 100px 200px 150px;

ブラウザでの表示は次のようになります。
※わかりやすいように背景に色をつけてます。

repeat()関数で同じ値を省略して記載する

並べるセルの数だけ大きさを記述する必要があるのですが、省略して次のように記載できます。

repeat(繰り返す回数, 繰り返す値)

この構文を当てはめると次のようになります。

grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: 100px 100px 100px;

//repeatで繰り返す値を省略
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(3, 100px);

セル同士の余白を設定する

セル間に余白を設けたい時があると思います。marginでも可能ですが、gapを使うと効率的に余白を設定できます。

column-gap: 10px; //横の余白を10pxにする
row-gap: 10px; //縦の余白を10pxにする

gap: 10px; //縦横の余白を10pxにする

並べるセルの数が決まってないときはgrid-auto[-rows / -column]を使う

grid-template-[-rows / -column]でセルの大きさを明示的に設定しない場合は、表示領領域に合わせてなんとなーくセルを並べてくれます。

grid-auto[-rows / -column]は、明示的に設定していないセルの大きさを指定できます。例えば、横に3個、縦に2個、合計6個のセルがある想定で、縦と横を次のようにします。

  grid-template-columns: 200px 200px 200px;
  grid-template-rows: 80px 80px;

ここに想定していない7個目のセルが追加になったので、結果的に縦に3個並ぶことになりました。
7個目のセルは初期設定からはみ出す形になります。高さを指定していないので、表示は次のようになりました。

こういったはみ出したセルに対して大きさを指定したいときgrid-auto[-rows または -columns]を使います。
縦の大きさを指定するときはgrid-auto-rowsを使います。

以下は、はみ出したセルの高さを100pxにしています。

grid-template-columns: 200px 200px 200px;
grid-template-rows: 80px 80px;
grid-auto-rows: 100px;

はみ出したセルに高さが100pxで設定されました!

よくあるのが、横を何個並べるかは決まってて、縦は決まっていないときです。
その場合は、grid-template-rowsで明示的に高さを指定せず、grid-auto-rowsだけを設定します。

grid-template-columns: 200px 200px 200px;
grid-auto-rows: 100px;

そうすると全ての高さが自動的に100pxになります。

これでグリッドレイアウトをCSSで表現できました!

幅や高さは固定ではなく可変で設定したい!

高さや幅をpxで指定すると、セルの大きさは固定になります。
レスポンシブだと幅は変動になりますし、高さは理由がない限りコンテンツ量よって変わります。

px以外に指定できる値を見ていきます。

単位「fr」を使って横幅を比率で表示する

幅や高さをpxや%で指定しても良いのですが、gridで使える「fr」という単位があります。
これは表示領域に合わせて、セルを比率で分割できるものです。
以下は横に3等分、同じ比率で表示します。

grid-template-columns: 1fr 1fr 1fr;

frで設定したセルは、表示領域の大きさに合わせて幅が変化しています。pxは固定値なので、当然大きさは変わりません。

frはpxや%など、他の単位と一緒に使用できます。
例えば、以下のように横幅の一部をpxで固定し、残りのセルを流動にすることもできます。

grid-template-columns: 100px 3fr 1fr;

全体の大きさから固定値(100px)をマイナスした、残りの領域に対して3対1の割合で分割されています。

「auto」でセルのコンテンツ量に合わせて表示する

frはセルを表示領域の比率で分割できますが、内包するコンテンツ量に応じて、大きさを伸縮したいことがあると思います。その場合はautoを使います。

以下は最初の高さを80pxで固定して、残りの高さはコンテンツの量に合わせて表示します。

grid-template-rows: 80px auto;

「minmax()」で最小値と最大値を決めておきたい

minmax()はCSSの関数です。以下のように最小値と最大値を,(カンマ)で区切って設定します。

minmax(最小値, 最大値)

以下は、縦の最小値を80px、最大値をautoにしています。

grid-auto-rows: minmax(80px, auto);

高さが80px以上になったらautoになり、コンテンツ量に応じた高さになります。

「repeat()」と「minmax()」でコンテンツの大きさに合わせて要素を繰り返し配置する

同じ値を繰り返すrepeat()、要素の最小値と最大値を設定するminmax()。これらを合わせて使うことで、メディアクエリを使うことなくレスポンシブ対応ができます!

構文は次の通りになります。

repeat(auto-fit / auto-fill, minmax(最小値, 最大値));

以下は90px〜1frに伸縮するセルを繰り返し横に並べます。

grid-template-columns: repeat(auto-fill, minmax(90px, 1fr));

繰り返す回数にauto-fitauto-fillを、繰り返す値にminmax()を指定するのがポイントです。

要素を繰り返し配置するにはauto-fitかauto-fillを指定する

ここで初めて見る値、auto-fitauto-fillがあります。
違いは以下のサンプルをご確認ください。auto-fitauto-fill以外は同じ値を設定しています。
※横幅は90px〜1frで伸縮します。

並べる個数をプルダウンから選ぶと、表示の違いを確認できます。

▼並べる要素の数を選択してください

要素を繰り返し並べる auto-fit

grid-template-columns: repeat(auto-fit, minmax(90px, 1fr));

item1
item2
item3
item4

要素を繰り返し並べる auto-fill

grid-template-columns: repeat(auto-fill, minmax(90px, 1fr));

item1
item2
item3
item4

auto-fitとauto-fillの違い

上記のサンプルで、セルの数が4個の時、auto-fitは余った要域にぴったり収まるように要素が引き伸ばされているのに対し、auto-fillは余白があります。

この余白を開発ツールで調べたところ、次のような表示になりました。

auto-fillは、余った領域に空のセルを作っているようです。この領域だと、あと4つ分のセルが表示できるスペースがあるということです。

ちなみに、セルの数を10個にしたら表示に違いはありませんでした。
余った領域の扱いが違うので、状況によって使い方を分ければ良さそうです。

このコードのサンプルは以下からも確認できます!

See the Pen Untitled by donguri2020 (@m-ke) on CodePen.

複数のグリッドをまたがって、セルを結合する

セルを結合すると、このような複雑なレイアウトも簡単に実装できます。

CodePenで実際の表示を確認できます!
表示領域が768px以下は、最初のコンテンツが1カラムで、以降のコンテンツが2カラムになります。
大きな画面で確認する場合、右上のCodePenのロゴをクリックしてください。

See the Pen Untitled by donguri2020 (@m-ke) on CodePen.

HTMLは次の通り非常にシンプルです。レイアウトの為だけのDIV要素も必要ないです。

<div class="contents">
 <div>コンテンツ1</div>
 <div>コンテンツ2</div>
 <div>コンテンツ3</div>
 <div>コンテンツ4</div>
 <div>コンテンツ5</div>
 <div>コンテンツ6</div>
 <div>コンテンツ7</div>
</div>

gridに関するCSSを抜き出したのがこちらです。

.contents {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 200px;
  grid-auto-rows: 100px;
  gap: 10px;
  & > div:nth-child(1) {
    grid-column: span 2;
  }
  @media screen and (min-width: 768px), print {
    grid-template-columns: repeat(3, 1fr);
    grid-template-columns: 300px;
    grid-auto-rows: 100px;
    & > div:nth-child(1) {
      // grid-column : 1 / 4;
      grid-column: span 3;
    }
    & > div:nth-child(2) {
        // grid-row: 2 / 4;
        grid-row: span 2;
    }
    & > div:nth-child(7) {
      // grid-column : 1 / 4;
      grid-column: span 3;
    }
  }
}

結合するセルにCSSを設定する

gridを設定した親要素ではなく、子要素のセルにstyleを設定します。構文は次の通りになります。

grid-column: (横の開始線番号) / (横の終了線番号)
grid-row : (縦の開始線番号) / (縦の終了線番号)

線番号とは

ここで、線番号という概念が出てきます。
Chromeのデベロッパーツールでgridレイアウトを確認すると、次のような番号が表示されます。

セルの境界に番号が振られていますが、これが線番号です。

線番号で結合するセルを設定する

例えば横に4個のセル(横幅1fr)が並んでいる線番号は次のようになります。
※マイナスの番号もありますが省略します。

1番目の「コンテンツ1」に線番号1 / 3 を設定します。

grid-column: 1 / 3

図で見ると、線番号1から3の範囲になります。※黄色く色付けした箇所になります。

こちらが実際にCSSを適用した表示になります。「コンテンツ1」の表示が、線番号1〜3にまたがって表示されているのが分かります。

線番号で指定した範囲にセルが表示されることが分かりました。

CSSを設定する要素(セル)を意識する

セルの結合でハマったのは、こちらです、、。
先ほどは「コンテンツ1」を2カラム分結合しましたが、真ん中のセル(線番号2〜4)を結合したい!とした場合です。
線番号で範囲を表すと2 / 4になります。

grid-column: 2 / 4;

このCSSを「コンテンツ1」にあてると、このように左に空白が空いています、、。

確かに線番号2から4の範囲に「コンテンツ1」が表示されているので正しい挙動です。
これを真ん中で結合する場合、「コンテンツ1」ではなく、「コンテンツ2」にCSSをあてます。

これで思った通りの表示を実装できました!

このコードのサンプルは以下からも確認できます!

See the Pen grid-layout-sample2 by donguri2020 (@m-ke) on CodePen.

開始線番号からいくつのセルを結合するか設定する

余談ですが、線番号で指定する以外に、結合するセルを個数で指定できます。
構文は次の通りです。

grid-column: (横の開始線番号) / (span セル数)
grid-row : (縦の開始線番号) / (span セル数)

考え方は、線番号で指定する方法と同じです。
結合するセルの数で指定できるので分かりやすいかもしれません。

参考サイト

グリッドレイアウトの基本概念 - CSS: カスケーディングスタイルシート | MDN
CSS グリッドレイアウトは、二次元グリッドシステムを CSS にもたらします。グリッドは、主要なページ領域や小さなユーザーインターフェイス要素のレイアウトに利用できます。この記事では、 CSS グリッドレイアウトと、 CSS Grid L...
CSS Grid Layout を極める!(基礎編) - Qiita
0. はじめにCSS Grid Layout(グリッドレイアウト)は、2次元レイアウト を、HTML/CSS を使って簡単・自由に操作できる、CSSの新しい機能です。格子状のマス目のグリッドに好…

まとめ

グリッドレイアウトは、すぐれたジェネレータがあるので、実際はそちらを使ってコーディングすることが多いです。ただ、基本を知っていないと改修ができないので、基礎的な使い方をまとめました。

コメント