25人がいいねしました

更新日

【CSS Grid 入門編】動画解説で手を動かしながら学ぶ!3つのサンプルと課題で基礎をマスター

web兄さん

CSSのGrid、みなさんはどれくらい使いこなしていますか?

現役でWeb制作をしている方でも意外と実務で使うレベルに落とし込めている人はいないのではないでしょうか?

  • 「あのタイル風のレイアウトできるやつね」
  • flexの方が直感的だしgridは使い所がイマイチわからない」

という方が多いのではないでしょうか。

それもそのはず、Gridの解説記事の多くが、以下のような「Gridなら複雑な配置のレイアウトができるよ!」というところまでの解説しかしていません。

ぶっちゃけ使用頻度が低いレイアウト…

そして多くの方が

「このレイアウト利用頻度少なくない?(笑)」

と思ってしまうわけです。


flexでもよくあるレイアウトはほぼ再現できますし、なにより直感的ですよね。gridでなければ再現できない場面に出くわすことが少ないため、学習機会を遠ざけるという結果になっています。(事実僕がそうでした)

そのため今回、【入門編】→【実務編】と分けて、CSS Gridを実務で使えるようにするための記事を作成しました!

どちらも手を動かしながらステップバイステップで理解できるようにこだわったので、他の記事よりも群を抜いて最初の1歩が理解しやすいと思います👍

【実務編】Gridに適したよくあるレイアウトを6パターン解説

本記事は【入門編】です。

ここからCSS Gridを実務レベルに落とし込むためには、基礎を理解した上でよくあるレイアウトでの実装方法を学ぶ必要があります。

ちなみに以下のレイアウトは1つ目を除きFlexよりGridでの実装が適しているレイアウトです。

①左右反転
②カードレイアウト
③セルの端にそれぞれの要素を配置
④タイル風
⑤サイドバー+記事レイアウト
⑥コンテンツが少なくてもページの高さを保持

この【入門編】が良いと思った方はぜひ【実務編】へ進んでみてください。

入門編 → 実務編 → 他の記事で詳細なプロパティを吸収が理想

CSS Gridは関連プロパティが本当に多く、一般的なWeb制作のレイアウトだと正直手に余る機能もあります…

できることを網羅的に紹介している記事は多いのですが、必要な知識に絞ってまず使えるように理解させようという記事は僕の知る限りありませんでした。

そのため僕の執筆する記事では頻出する書き方に絞っています。

より高度な学習をしたい方は「入門編」→「実務編」とCSS Gridを学んだ後、より詳細なプロパティや値をMDNの記事などを参考に知識を付け足していくとスムーズだと思います。

GridとFlexの違いを理解するには頭を切り替える必要がある

これがめちゃくちゃ大事です。まずは直感的に理解する必要があるため以下の違いを確認してみましょう。

flexgridでそれぞれレイアウトさせる時のイメージをデザインソフトで再現してみました。

Flexで横並びさせる時のイメージ

flexboxでの横並びアプローチ
  1. とりあえず横並びにする(親にdisplay: flex
  2. アイテムごとの横幅をそれぞれ設定する(子にflex-basis

flexとりあえず横並びにしてから子要素ごとに横幅や伸縮率を設定していくイメージですよね。

Gridで横並びさせる時のイメージ

Gridの横並びのアプローチ
  1. コンテナをいくつの線で分割するか決める
  2. 線同士の間隔(グリッドの幅)を決める
  3. 線の間のエリアに子が配置される

gridは先にコンテナを分割して、そこに子要素(アイテム)を当てはめていきます。

つまり、

flexが「とりあえず横並びにしてから子要素の幅や配置を決めていく」のに対して、

girdは「先にどのように配置するかコンテナを分割して、そこに子要素を当てはめる

というイメージの違いとなります。

両者はベースとなる概念がそもそも全く違うのでflexの考え方を捨てないと絶対に混乱してしまいます。

web兄さん
なので、これからGridレイアウトの基礎を解説していきますが、flexのことは綺麗さっぱり忘れてください!

Gridに登場する用語を覚える

Gridにはややこしい用語がいくつか登場します。Gridの学習において最初に用語を詰め込みすぎると失敗するので、優先度をつけて必須な用語だけを深く、その他はあっさりと解説します。

コンテナ(親) > アイテム(子)

これは超基本ですね。ここだけは唯一flexと同じ考え方です。

<div class="grid">  👈コンテナ(親)
  <div class="grid__item">アイテムA</div>
  <div class="grid__item">アイテムB</div>
  <div class="grid__item">アイテムC</div>
</div>

上記の図をHTMLで表すとこのようになります。

レイアウトさせたい要素をアイテムと呼び、それ全体を囲っている親要素をコンテナと呼びます。

ライン(線)

先ほどの例で出てきた線のことです。

たとえば、さきほどのレイアウトでは以下のようにラインが引かれています。

ラインには「列(横)」と「行(縦)」があり、それぞれ左上を起点として番号が振られています。

トラック・セル・エリア

このあたりは覚えなくても後から必要に応じて感覚で理解できるので大丈夫です。

トラック
セル
エリア

具体的な書き方は後述しますが、上記は以下のようなコードを書いています。

Gridを実際に書いて基礎を理解しよう

それでは以下の簡単なサンプルを用いて、手を動かしながらgridの基礎を理解していきましょう。


最初は動画解説の方が理解しやすいので以下を見ながら一緒に手を動かしてみてください。

コピー用のHTML

<!DOCTYPE html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Grid</title>
  <style>
    body{
      max-width: 960px;
      margin: 100px auto;
    }
    .grid__item{
      color: #086EC9;
      background-color: #EFF7FF;
      border: solid 1px #086EC9;
      text-align: center;
      font-weight: bold;
    }
  </style>
</head>
<body>
  
  <div class="grid">
    <div class="grid__item _A">アイテムA(子)</div>
    <div class="grid__item _B">アイテムB(子)</div>
    <div class="grid__item _C">アイテムC(子)</div>
  </div>

  <style>

    /* 親 */
    .grid{

    }

    /* 子 */
    .grid__item{
      
    }

    .grid__item._A{
      
    }

    .grid__item._B{
      
    }

    .grid__item._C{
      
    }

  </style>

</body>
</html>

実際に追記したCSS

/* 親 */
.grid{
  display: grid;
  grid-template-columns: 660px 300px;
  grid-template-rows: 180px 180px;
}

/* 子 */
.grid__item{
  display: flex;
  justify-content: center;
  align-items: center;
}

.grid__item._A{
  grid-column: 1/2;
  grid-row: 1/3;
}

.grid__item._B{
  grid-column: 2/3;
  grid-row: 1/2;
}

.grid__item._C{
  grid-column: 2/3;
  grid-row: 2/3;
}

動画の要点を整理

プロパティセレクタ役割
display: gridグリッドレイアウトの定義。適用しただけでは見た目は変わらない。
grid-template-columns列をどの幅で区切るかを指定
grid-template-rows行をどの幅で区切るかを指定
grid-column列の何番目のラインから何番目のラインまでにその要素を配置するか。
開始/終了と「/」で区切って記述
grid-row行の何番目のラインから何番目のラインまでにその要素を配置するか。
開始/終了と「/」で区切って記述

1fr|幅を自動で割り振る

<div class="grid">
  <div class="grid__item _A">アイテムA(子)</div>
  <div class="grid__item _B">アイテムB(子)</div>
  <div class="grid__item _C">アイテムC(子)</div>
</div>

HTMLは先ほどと同じままで、CSSのみ以下に置き換えてみましょう。

/* 親 */
.grid{
  display: grid;
  grid-template-columns: 480px 1fr 1fr; /* この「fr」という単位がポイント */
  grid-template-rows: 180px;
}

/* 子 */
.grid__item{
  display: flex;
  justify-content: center;
  align-items: center;
}

すると表示結果は以下のようになったはずです。

grid-template-columns: 480px 1fr 1frと書くことで、なんとなく3列になっていることはわかりますが、1frという書き方がどういった幅なのかわかりませんよね。


frはコンテナを数字の比率で割り振ります。

今回の例であれば、960pxのうち1列目は480pxの絶対値で指定し、2、3列目は1:1の比率で残りの480pxを割り振るためそれぞれ240pxの列ができあがります。

例えば、以下の吹き出しレイアウトのように写真は固定で、吹き出し部分はレスポンシブさせたい時などに活用します。

片方が固定で残りをレスポンシブさせたい時に「fr」は使える

このように2列しかない場合grid-tempalte-columns: 160px 1frと書けば残りの列は目一杯広がってくれます。

比率を変えて割り振る

grid-tempalte-columns: 2fr 1fr 1frと書くことで、「2:1:1」の比率で列の幅を決めることができます。

2:1:1で自動配置したい場合

当然、grid-tempalte-columns: 3fr 2fr 1frと書けば比率を変更することは可能です。

複数列均等に並べたい場合

全てのアイテムを均等に配置したい場合は、列トラックの数だけ1frを記述します。

例えば3列で表示したい場合はgrid-tempalte-columns: 1fr 1fr 1frのように記述します。

gridの名の通り、グリッドレイアウトに適している

スマホ時は2列、デスクトップ時は3列にしたい場合は以下のように記述します。

/* モバイル */
.grid{  
  display: grid;
  grid-template-columns: 1fr 1fr; /* 均等に2列 */
}

/* デスクトップ */
@media (min-width:768px){
  .grid{
    grid-template-columns: 1fr 1fr 1fr; /* 均等に3列 */
  }
}

コピペ可能な確認用コード

<!DOCTYPE html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Grid</title>
  <style>
    body{max-width: 960px; margin: 100px auto;}
    h3{margin: 24px 0 10px;}
    p{margin: 0;}
    img{max-width: 100%; height: auto;}
  </style>
</head>
<body>
  
  <div class="grid">
  
    <div class="card">
      <img width="336" height="152" src="https://dummyimage.com/336x152/eff7ff/eff7ff.png" alt="dummy">
      <h3>記事タイトル</h3>
      <p>抜粋文章がはいります。抜粋文章がはいります。抜粋文章がはいります。</p>
    </div>

    <div class="card">
      <img width="336" height="152" src="https://dummyimage.com/336x152/eff7ff/eff7ff.png" alt="dummy">
      <h3>記事タイトル</h3>
      <p>抜粋文章がはいります。抜粋文章がはいります。抜粋文章がはいります。</p>
    </div>

    <div class="card">
      <img width="336" height="152" src="https://dummyimage.com/336x152/eff7ff/eff7ff.png" alt="dummy">
      <h3>記事タイトル</h3>
      <p>抜粋文章がはいります。抜粋文章がはいります。抜粋文章がはいります。</p>
    </div>

    <div class="card">
      <img width="336" height="152" src="https://dummyimage.com/336x152/eff7ff/eff7ff.png" alt="dummy">
      <h3>記事タイトル</h3>
      <p>抜粋文章がはいります。抜粋文章がはいります。抜粋文章がはいります。</p>
    </div>

    <div class="card">
      <img width="336" height="152" src="https://dummyimage.com/336x152/eff7ff/eff7ff.png" alt="dummy">
      <h3>記事タイトル</h3>
      <p>抜粋文章がはいります。抜粋文章がはいります。抜粋文章がはいります。</p>
    </div>
    
  </div>


  <style>
    
    /* モバイル */
    .grid{  
      display: grid;
      grid-template-columns: 1fr 1fr; /*均等に割る*/
    }
    
    /* デスクトップ */
    @media (min-width:768px){
      .grid{
        grid-template-columns: 1fr 1fr 1fr; /*均等に割る*/
      }
    }

    /* 余白をつけるためのコード */
    .grid{
      margin-right: -24px;
    }
    .card{
      margin-right: 24px;
      margin-bottom: 40px;
    }
    
  </style>

</body>
</html>

column-gap / row-gap|グリッドに余白をつける

先ほどのカードデザインのように通常のレイアウトであれば余白がついていることの方が多いですよね。

先ほどの例のサンプルコードではmarginでアイテムごとの余白を作っていましたが、gapを使用した方が簡単です。(ちなみにflexでもこのプロパティは使用できます)

プロパティ役割
row-gappx,%,em,remなど大体の単位が使用可能行の余白(縦の余白)
column-gappx,%,em,remなど大体の単位が使用可能列の余白(横の余白)
gappx,%,em,remなど大体の単位が使用可能まとめて[行 列]の順に指定する
例)gap: 40px 24px

gapはトラック(列と行)の間にだけ付く

この例では以下のようにCSSを記述します。

.grid{  
  row-gap: 40px; /*行の間隔*/
  column-gap: 24px; /*列の間隔*/
}

コピペ可能な確認用コード

<!DOCTYPE html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Grid</title>
  <style>
    body{max-width: 960px; margin: 100px auto;}
    h3{margin: 24px 0 10px;}
    p{margin: 0;}
    img{max-width: 100%; height: auto;}
  </style>
</head>
<body>
  
  <div class="grid">
  
    <div class="card">
      <img width="336" height="152" src="https://dummyimage.com/336x152/eff7ff/eff7ff.png" alt="dummy">
      <h3>記事タイトル</h3>
      <p>抜粋文章がはいります。抜粋文章がはいります。抜粋文章がはいります。</p>
    </div>

    <div class="card">
      <img width="336" height="152" src="https://dummyimage.com/336x152/eff7ff/eff7ff.png" alt="dummy">
      <h3>記事タイトル</h3>
      <p>抜粋文章がはいります。抜粋文章がはいります。抜粋文章がはいります。</p>
    </div>

    <div class="card">
      <img width="336" height="152" src="https://dummyimage.com/336x152/eff7ff/eff7ff.png" alt="dummy">
      <h3>記事タイトル</h3>
      <p>抜粋文章がはいります。抜粋文章がはいります。抜粋文章がはいります。</p>
    </div>

    <div class="card">
      <img width="336" height="152" src="https://dummyimage.com/336x152/eff7ff/eff7ff.png" alt="dummy">
      <h3>記事タイトル</h3>
      <p>抜粋文章がはいります。抜粋文章がはいります。抜粋文章がはいります。</p>
    </div>

    <div class="card">
      <img width="336" height="152" src="https://dummyimage.com/336x152/eff7ff/eff7ff.png" alt="dummy">
      <h3>記事タイトル</h3>
      <p>抜粋文章がはいります。抜粋文章がはいります。抜粋文章がはいります。</p>
    </div>
    
  </div>


  <style>
    
    /* モバイル */
    .grid{  
      
      display: grid;
      grid-template-columns: 1fr 1fr; /*均等に割る*/

      row-gap: 40px; /*行の間隔*/
      column-gap: 24px; /*列の間隔*/
    
    }
    
    /* デスクトップ */
    @media (min-width:768px){
      .grid{
        grid-template-columns: 1fr 1fr 1fr; /*均等に割る*/
      }
    }
    
  </style>

</body>
</html>

gapはアイテムの間にしか余白ができない

gapの良いポイントはアイテム同士の間にしか余白が生まれないことです。

marginで余白をつける場合は打ち消しが必要だったり、justify-contetn: space-betweenも最後の行だけ数が異なると擬似要素を入れたり面倒ごとが多いですよね。

両端揃えだと最後の行だけ空間ができる
web兄さん
とりあえずGridレイアウトを使う時はgapで余白を作る方が楽と覚えておきましょう!
個別に余白を変えたい時は?
gapでは個別の余白を設定できません。そのためトラックの幅を調整したり、marginと共存させるなどの工夫が必要です。
ただ、余白をそれぞれ設定する必要がある場合はgridでの実装がそもそも向いてない要件である可能性もあります。

repeat()|繰り返し

今回のように3列の場合は楽ですが、仮に6列が均等な場合は以下のような記述になり大変ですよね。

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

列の分だけ同じことを書くのは大変…

その場合は繰り返し同じことを書く箇所にrepeat(繰り返す数, 値)で記述をスマートにすることができます。(grid-template-rowでも使用可)

grid-template-columns: repeat(6,1fr); /* 1fr 1fr 1fr 1fr 1fr 1fr と同じ */

一部だけ繰り返し

全て同じ値であれば単純に繰り返せば良いですが、以下のように列の幅が異なる場合、一部だけ繰り返すこともできます。

grid-template-columns: repeat(3,1fr) 320px 1fr; /* 1fr 1fr 1fr 320px 1fr と同じ */

まとめ|課題にチャレンジしよう

それではこれらを踏まえて以下のレイアウトを自力で組んでみましょう。

課題用HTML

<!DOCTYPE html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Grid</title>
  <style>
    body{
      max-width: 960px;
      margin: 100px auto;
    }
  </style>
</head>
<body>
  

  <!-- 

    あえてHTMLの順番をごちゃっとさせています。
    セレクタに注意してください。

   -->

  <div class="grid">
    <div class="grid__item _A">
      <img src="https://dummyimage.com/960x180/a7cfe8/000000.png" alt="960x180">
    </div>
    <div class="grid__item _B">
      <img src="https://dummyimage.com/240x360/a7cfe8/000000.png" alt="240x360">
    </div>
    <div class="grid__item _C">
      <img src="https://dummyimage.com/500x160/a7cfe8/000000.png" alt="500x160">
    </div>
    <div class="grid__item _D">
      <img src="https://dummyimage.com/440x540/a7cfe8/000000.png" alt="440x540">
    </div>
    <div class="grid__item _E">
      <img src="https://dummyimage.com/240x360/a7cfe8/000000.png" alt="240x360">
    </div>
  </div>

  <style>

    /* 親 */
    .grid{
      
    }

    /* 子 */
    .grid__item._A{  /* 960x180 */
      
    }

    .grid__item._B{  /* 240x360 */
      
    }

    .grid__item._C{  /* 500x160 */
      
    }

    .grid__item._D{  /* 440x540 */
      
    }

    .grid__item._E{  /* 240x360 */
      
    }

  </style>

</body>
</html>

※余白は20pxで組んであります。

一見退屈なレイアウトに見えますが、今回の入門編で覚えるべき以下は全て詰まっています。

  • grid / grid-template-column / grid-template-row
  • grid-row / grid-column
  • fr / gap / repeat()

逆に言えば、これらを余裕を持って理解している状態でないと「実務編」の解説に苦戦すること請け合いです。

web兄さん
とりあえずGridレイアウトを使う時はgapで余白を作る方が楽と覚えておきましょう!

解答コードを見る

<!DOCTYPE html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Grid</title>
  <style>
    body{
      max-width: 960px;
      margin: 100px auto;
    }
  </style>
</head>
<body>
  
  <div class="grid">
    <div class="grid__item _A">
      <img src="https://dummyimage.com/960x180/a7cfe8/000000.png" alt="960x180">
    </div>
    <div class="grid__item _B">
      <img src="https://dummyimage.com/240x360/a7cfe8/000000.png" alt="240x360">
    </div>
    <div class="grid__item _C">
      <img src="https://dummyimage.com/500x160/a7cfe8/000000.png" alt="500x160">
    </div>
    <div class="grid__item _D">
      <img src="https://dummyimage.com/440x540/a7cfe8/000000.png" alt="440x540">
    </div>
    <div class="grid__item _E">
      <img src="https://dummyimage.com/240x360/a7cfe8/000000.png" alt="240x360">
    </div>
  </div>

  <style>

    /* 親 */
    .grid{
      display: grid;
      grid-template-columns: 440px repeat(2,1fr);
      grid-template-rows: 180px 360px 160px;
      gap: 20px;
    }

    /* 子 */
    .grid__item._A{  /* 960x180 */
      grid-row: 1/2;
      grid-column: 1/4;
    }

    .grid__item._B{  /* 240x360 */
      grid-row: 2/3;
      grid-column: 2/3;
    }

    .grid__item._C{  /* 500x160 */
      grid-row: 3/4;
      grid-column: 2/4;
    }

    .grid__item._D{  /* 440x540 */
      grid-row: 2/4;
      grid-column: 1/2;
    }

    .grid__item._E{  /* 240x360 */
      grid-row: 2/3;
      grid-column: 3/4;
    }

  </style>

</body>
</html>

FlexboxとCSS Gridの違いをさらに理解したい方向け

この入門編を終えてから以下の記事を読むとより一層、FlexboxとCSS Gridの特徴の違いへの理解が深まります👍

完璧だった方はぜひ「実務編」へ

解答コードと自身が書いたコードは同じでしたか?同じだった方は素晴らしいです👏

CSS Grid 実務編】へ進んで明日から仕事でCSS Gridを積極的に使っていきましょう!

スクール越えの圧倒的なコスパ1ヶ月でWeb制作を身に着ける

プロのメンターサポート付き実務レベルのコーディングカリキュラム

詳細を今すぐチェック!

ギャクサンで作成するポートフォリオサイトのイメージ

記事では見れない豆知識

圧倒的なコスパを体感1ヶ月でWeb制作を身に着ける

プロのメンターサポート付き実務レベルのコーディングカリキュラム

詳細を今すぐチェック!

ギャクサンで作成するポートフォリオサイトのイメージ