26人がいいねしました
更新日
【CSS Grid 入門編】動画解説で手を動かしながら学ぶ!3つのサンプルと課題で基礎をマスター
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の違いを理解するには頭を切り替える必要がある
これがめちゃくちゃ大事です。まずは直感的に理解する必要があるため以下の違いを確認してみましょう。
flex
とgrid
でそれぞれレイアウトさせる時のイメージをデザインソフトで再現してみました。
Flexで横並びさせる時のイメージ
- とりあえず横並びにする(親に
display: flex
) - アイテムごとの横幅をそれぞれ設定する(子に
flex-basis
)
flex
はとりあえず横並びにしてから子要素ごとに横幅や伸縮率を設定していくイメージですよね。
Gridで横並びさせる時のイメージ
- コンテナをいくつの線で分割するか決める
- 線同士の間隔(グリッドの幅)を決める
- 線の間のエリアに子が配置される
grid
は先にコンテナを分割して、そこに子要素(アイテム)を当てはめていきます。
つまり、
flex
が「とりあえず横並びにしてから子要素の幅や配置を決めていく」のに対して、
gird
は「先にどのように配置するかコンテナを分割して、そこに子要素を当てはめる」
というイメージの違いとなります。
両者はベースとなる概念がそもそも全く違うのでflexの考え方を捨てないと絶対に混乱してしまいます。
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
の列ができあがります。
例えば、以下の吹き出しレイアウトのように写真は固定で、吹き出し部分はレスポンシブさせたい時などに活用します。
このように2列しかない場合grid-tempalte-columns: 160px 1fr
と書けば残りの列は目一杯広がってくれます。
比率を変えて割り振る
grid-tempalte-columns: 2fr 1fr 1fr
と書くことで、「2:1:1」の比率で列の幅を決めることができます。
当然、grid-tempalte-columns: 3fr 2fr 1fr
と書けば比率を変更することは可能です。
複数列均等に並べたい場合
全てのアイテムを均等に配置したい場合は、列トラックの数だけ1fr
を記述します。
例えば3列で表示したい場合はgrid-tempalte-columns: 1fr 1fr 1fr
のように記述します。
スマホ時は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-gap | px,%,em,remなど大体の単位が使用可能 | 行の余白(縦の余白) |
column-gap | px,%,em,remなど大体の単位が使用可能 | 列の余白(横の余白) |
gap | px,%,em,remなど大体の単位が使用可能 | まとめて[行 列]の順に指定する 例) gap: 40px 24px |
この例では以下のように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
も最後の行だけ数が異なると擬似要素を入れたり面倒ごとが多いですよね。
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()
逆に言えば、これらを余裕を持って理解している状態でないと「実務編」の解説に苦戦すること請け合いです。
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を積極的に使っていきましょう!