実はそれほど難しくない、CSS Grid Layoutの使い方
2024年 2月26日 Posted 野々瀨(フロントエンドエンジニア)
IEのサポートが終了したことで、本格的にCSSのGrid Layoutが使用できるようになりました。もちろんIE11でも使えてはいましたが、プロパティ名が違っていたり、対応するプロパティが少なかったりと問題があり、IEではなかなか使いづらい感じでした(当時はSafariも使用することができず、対応に苦労した覚えがあります)。
今回はそんなCSS Grid Layoutの使い方をご紹介しようと思います。
そもそもCSS Grid Layoutって?
CSS Grid Layout(以降はグリッドレイアウトと呼称)は2次元のレイアウトを簡単に表現ができる機能です。Excelのセルのようなもので、格子状に分割されたマス目に要素を配置してレイアウトしていきます。グリッドシステム(レイアウトグリッド)のような使い方で、ガイドに沿ってレイアウトを組むことができます。
また、Flexible Box Layoutと同じように、幅や高さをフレキシブルに表現することができます。
Flexible Box Layoutとの違い
Flexible Box Layout(以降はフレキシブルレイアウトと呼称)とは次のような違いがあります。
違い | グリッドレイアウト | フレキシブルレイアウト |
---|---|---|
配置方法 | 2次元 | 1次元 |
配置位置や方向 | 自由な位置に配置ができる | 一方方向のみ |
配置可能なアイテム数 | 決められた分割数の領域のみ | 無制限 |
幅に応じた自動折り返し | なし | あり |
配置方法
グリッドレイアウトは2次元であるのに対し、フレキシブルレイアウトは1次元です。
配置位置や方向
グリッドレイアウトは決められた領域内であれば自由な位置に配置ができるのに対し、フレキシブルレイアウトは水平方向か垂直方向のどちらか一方の方向での配置です。
幅に応じた自動折り返し
グリッドレイアウトは幅に応じてアイテムを自動的に折り返すことはありませんが、フレキシブルレイアウトは幅に応じてアイテムを自動的に折り返すことができます。
配置可能なアイテム数
グリッドレイアウトはあらかじめ決められた分割数の領域内で配置するのに対し、フレキシブルレイアウトは特に数の指定がなく無制限に並びます。ただし、グリッドレイアウトは暗黙的に列または行を分割(生成)する機能を持ち、自動的に配置しているときにアイテム数が行列数を超える場合、配置する方向にそって行や列を追加してくれます。暗黙的な分割については見出し「暗黙的な行列の分割(生成)」をご覧ください。
折り返し
グリッドレイアウトはグリッドに沿った配置を行うため折り返しする機能はありません。フレキシブルレイアウトは親要素の幅を基準に、はみ出した子の要素を折り返すことができます。ただし、グリッドレイアウトは「配置可能なアイテム数」でも説明したとおり、暗黙的な行列の追加により自動配置する機能を持ちますので、折り返されたように配置されることがあります。
基本構成
コンテナ
配置を行う基本となる領域が「コンテナ」です。これをベースにして要素を配置します。
アイテム
配置を行う要素そのものが「アイテム」です。コンテナ直下にある要素は全てアイテムとなります。つまり、配置した要素がある場合は、コンテナ直下にいる必要があります。
ライン
水平・垂直に分割した線が「ライン」です。基本的な軸は水平は左から右へ、垂直は上から下で、番号が1から振られています。
負の値として数えることもでき、軸が水平は右から左へ、垂直は下から上で-1から振られています。
トラック
行または列が「トラック」です。ラインとラインの間の領域のことを指します。
セル
アイテムを配置する一つのマス目が「セル」です。
エリア
アイテムを設置する範囲の領域が「エリア」です。範囲であることから、隣接したセル同士が結合された状態の領域や、一つのセルでもエリアとなります。
使い方
基本的な構成
まずHTMLを用意します。ここでは次のようにコンテナ要素とアイテム要素の簡単なものを用意しています。
<div class="container">
<div class="item">A</div>
<div class="item">B</div>
<div class="item">C</div>
<div class="item">D</div>
<div class="item">E</div>
<div class="item">F</div>
</div>
次にCSSを用意します。display
プロパティのgrid
をコンテナ要素へ指定します。
.container {
display: grid;
}
これで最低限の記述は完了です。
次にトラックを確保します。トラックの確保は行をgrid-template-columns
プロパティ、列をgrid-template-rows
プロパティで行います。grid-template-rows
プロパティは分割したい行数分の高さを、スペースで区切って指定します。grid-template-columns
プロパティは分割したい列数分の幅を、スペースで区切って指定します。これらのプロパティを指定しますと、指定した分割数に応じてアイテムが自動的に配置されます。
このプロパティはコンテナに対して指定することで行えます。
例えば次のように指定しますと、2行3列のトラックを確保します。
.container {
display: grid;
grid-template-columns: 100px 150px 1fr;
grid-template-rows: 50px 70px;
}
autoとfrの単位について
幅や高さ(長さ)はpxなど基本的な単位を使用することができますが、auto
やfr
という値も指定することができます。
auto
はアイテムの長さに応じて自動的に調整されます。
fr
はコンテナの長さにおける残りの長さの占有率です。grid-template-columns: 100px 1fr 2fr 3fr;
とした場合、1列目は100px、2列目~4列目は残りの長さを1 + 2 + 3 = 6分割し、その割合で割り当てられます。つまり2列目は残りの長さの6分の1の長さが割り当てられ、3列目は残りの長さの6分の2の長さが割り当てられ、4列目は残りの長さの6分の3の長さが割り当てられます。
.container {
display: grid;
grid-template-columns: 100px 1fr 2fr 3fr;
grid-template-rows: auto auto;
}
幅や高さが連続して同じ値の時の一括指定
grid-template-columns
プロパティとgrid-template-rows
プロパティは、repeat
関数を使用することで、幅や高さが連続して同じ値の時に一括指定することができます。構文はrepeat(繰り返す数, 値)
と指定します。
.container {
display: grid;
grid-template-columns: 1fr repeat(2, 100px) auto;
grid-template-rows: repeat(4, auto);
}
幅に応じたアイテムの埋め方
repeat
関数の第一引数には幅に応じたアイテムの埋める方法を指定することもできます。auto-fill
とauto-fit
という値を指定することができます。
auto-fill
はアイテムが自動で配置された際にできた残りの余白に対して、新たなグリッドを生成します。
.container {
display: grid;
grid-template-columns: repeat(auto-fill, 70px);
}
また、minmax
関数と組み合わせることで、残りの余白が最小値に満たした場合にグリッドを生成し、それ以外は最大値の幅としてアイテムの幅が設定されるようになります。
.container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(70px, 1fr));
}
auto-fit
はrepeat
関数の第二引数で指定したアイテムの幅や高さが、親要素の幅や高さに収まるアイテムをその方向に並べ、収まらない場合は収まらない分の余白を残し、次の行または列に折り返して並びます。
.container {
display: grid;
grid-template-columns: repeat(auto-fit, 70px);
}
また、minmax
関数と組み合わせることで、余白がアイテムの幅(最小値)を満たすまではアイテムの幅を最大値として表示し、それを超える場合は次の行または列に折り返して並びます。
.container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(70px, 1fr));
}
ラインを基準にアイテムを配置
grid-row
プロパティまたはgrid-column
プロパティを使用しますと、ラインを基準にアイテムを配置することができます。grid-row
プロパティは行の位置、grid-column
プロパティは列の位置の指定を行います。それぞれのプロパティはアイテムに対して指定し、値は次のいずれかで指定します。
.item {
/* grid-row */
grid-row: 行の開始番号;
grid-row: 行の開始番号 / 行の終了番号;
/* grid-column */
grid-column: 列の開始番号;
grid-column: 列の開始番号 / 列の終了番号;
}
grid-row
プロパティはgrid-row-start
プロパティとgrid-row-end
プロパティのショートハンドで、grid-column
プロパティはgrid-column-start
プロパティとgrid-column-end
プロパティのショートハンドです。
.item {
/* grid-row */
grid-row: grid-row-start;
grid-row: grid-row-start / grid-row-end;
/* grid-column */
grid-column: grid-column-start;
grid-column: grid-column-start / grid-column-end;
}
.container {
display: grid;
grid-template-columns: repeat(3, 50px);
grid-template-rows: repeat(4, 50px);
}
/* A */
.item:nth-child(1) {
grid-row: 1;
}
/* B */
.item:nth-child(2) {
grid-row: 1;
grid-column: 2;
}
/* C */
.item:nth-child(3) {
grid-row: 1 / 3;
grid-column: 3;
}
/* D */
.item:nth-child(4) {
grid-row: 2 / 4;
grid-column: 1 / 3;
}
/* E */
.item:nth-child(5) {
grid-row: 3;
}
/* F */
.item:nth-child(6) {
grid-row: 4;
grid-column: 2 / 4;
}
また、grid-row-end
プロパティ部分やgrid-column-end
プロパティ部分はspan
キーワードを使用しますと、ライン番号ではなく範囲で指定することができます。例えば、span 3
と指定すれば開始行または開始列から三つのセルということになります。
.container {
display: grid;
grid-template-columns: repeat(4, 50px);
grid-template-rows: repeat(3, 50px);
}
.item {
grid-row: 2 / 4;
grid-column: 2 / span 3;
}
なお、grid-row
プロパティとgrid-column
プロパティはショートハンドgrid-area
プロパティがあります。値は次のいずれかで指定します。
.item {
grid-area: grid-row-start;
grid-area: grid-row-start / grid-column-start;
grid-area: grid-row-start / grid-row-end / grid-column-start;
grid-area: grid-row-start / grid-row-end / grid-column-start / grid-column-end;
}
エリアに名前を付けてアイテムを配置
grid-template-areas
プロパティとgrid-area
プロパティを使用しますと、エリアに名前を付けてアイテムを配置することができます。grid-template-areas
プロパティは領域を定義するために使用し、grid-area
プロパティは当てはめる領域を指定します。grid-template-areas
プロパティはコンテナに対して指定し、grid-area
プロパティはアイテムに対して指定します。
grid-template-areas
プロパティは値はセルをスペースで区切ってクォーテーションでくくったものを行とし、さらにスペースで区切ることで列とすることで指定します。grid-area
プロパティは当てはめる領域の名前を指定します。
<div class="container">
<div class="header">Header</div>
<div class="main">Main</div>
<div class="side">Side</div>
<div class="footer">Footer</div>
</div>
.container {
display: grid;
grid-template-areas:
"header header"
"main side"
"footer side";
}
.header {
grid-area: header;
}
.main {
grid-area: main;
}
.side {
grid-area: side;
}
.footer {
grid-area: footer;
}
ラインに名前を付けて行列の大きさを設定
grid-template-columns
プロパティとgrid-template-rows
プロパティは、各ラインに対して名前を付けて指定することができます。名前を付けた後にgrid-row
プロパティやgrid-column
プロパティに割り当てたい名前を指定することで、その割り当てられた名前と一致する幅や高さが反映されます。
例えば四つの列のラインがあったとした場合、grid-template-columns: [line1] 1fr [line2] 2fr [line3] 3fr [line4]
という感じで、ラインとトラックをスペースで交互に区切り、ラインは角括弧に付けたい名前を指定します。また、特に名前を付ける必要がなければ、grid-template-columns: [line1] 1fr 2fr [line3] 3fr
という感じで、名前の部分は何も指定せずに続けて値を指定します。
.container {
display: grid;
grid-template-columns: [aaa] 1fr [bbb] 2fr [ccc] 3fr [ddd];
grid-template-rows: repeat(3, auto);
}
アイテムの整列
アイテムの整列は幾つかのプロパティがあります。
アイテムを一括で整列
アイテムを一括で整列することができます。水平(X軸)方向はjustify-items
プロパティ、垂直(Y軸)方向はalign-items
プロパティを使用します。それぞれのプロパティはコンテナに対して指定します。指定可能な値は次のとおりで、初期値はstretch
です。
値 | justify-items | align-items |
---|---|---|
start | 左寄せ | 上寄せ |
center | 左右中央寄せ | 上下中央寄せ |
end | 右寄せ | 下寄せ |
stretch | 両端寄せ | 両端寄せ |
baseline | ベースライン寄せ | ベースライン寄せ |
justify-itemsプロパティの値の例:
align-itemsプロパティの値の例:
.container {
display: grid;
grid-template-columns: repeat(4, 50px);
grid-template-rows: repeat(3, 50px);
align-items: center;
justify-items: end;
}
また、justify-items
プロパティとalign-items
プロパティはショートハンドとしてplace-items
プロパティで一括指定ができます。place-items
プロパティはplace-items: align-items justify-items;
と指定できますが、place-items: center;
のように一つ目の値だけを指定した場合、二つ目は一つ目と同じ値を指定したことと同じになります。
.container {
display: grid;
grid-template-columns: repeat(4, 50px);
grid-template-rows: repeat(3, 50px);
place-items: center end;
}
個別のアイテムを整列
個別にアイテムを整列することができます。水平(X軸)方向はjustify-self
プロパティ、垂直(Y軸)方向はalign-self
プロパティを使用します。それぞれのプロパティはコンテナに対して指定します。指定可能な値は次のとおりで、初期値はstretch
です。
値 | justify-self | align-self |
---|---|---|
start | 左寄せ | 上寄せ |
center | 左右中央寄せ | 上下中央寄せ |
end | 右寄せ | 下寄せ |
stretch | 両端寄せ | 両端寄せ |
baseline | ベースライン寄せ | ベースライン寄せ |
.container {
display: grid;
grid-template-columns: repeat(4, 50px);
grid-template-rows: repeat(3, 50px);
}
.item:nth-child(2) {
align-self: center;
}
.item:nth-child(3) {
justify-self: end;
}
また、justify-self
プロパティとalign-self
プロパティはショートハンドとしてplace-self
プロパティで一括指定ができます。place-self
プロパティはplace-self: align-self justify-self;
と指定できますが、place-self: center;
のように一つ目の値だけを指定した場合、二つ目は一つ目と同じ値を指定したことと同じになります。
.item:nth-child(2) {
place-self: center end;
}
全てのアイテム全体を整列
コンテナ要素を基準にアイテム全体を整列することができます。水平(X軸)方向はjustify-content
プロパティ、垂直(Y軸)方向はalign-content
プロパティを使用します。それぞれのプロパティはコンテナに対して指定します。指定可能な値は次のとおりで、初期値はstretch
です。
値 | justify-content | align-content |
---|---|---|
start | 左寄せ | 上寄せ |
center | 左右中央寄せ | 上下中央寄せ |
end | 右寄せ | 下寄せ |
stretch | 両端寄せ | 両端寄せ |
space-between | アイテム間の余白を均等 | アイテム間の余白を均等 |
space-around | 先端・終端を含めアイテム間の余白を均等 ※ 先端と終端の余白はアイテム間の2分の1 |
先端・終端を含めアイテム間の余白を均等 ※ 先端と終端の余白はアイテム間の2分の1 |
justify-contentプロパティの値の例:
align-contentプロパティの値の例:
.container {
display: grid;
grid-template-columns: repeat(3, auto);
grid-template-rows: repeat(2, auto);
align-content: center;
justify-content: end;
width: 150px;
height: 100px;
}
また、justify-content
プロパティとalign-content
プロパティはショートハンドとしてplace-content
プロパティで一括指定ができます。place-content
プロパティはplace-content: align-content justify-content;
と指定できますが、place-content: center;
のように一つ目の値だけを指定した場合、二つ目は一つ目と同じ値を指定したことと同じになります。
.container {
display: grid;
grid-template-columns: repeat(3, auto);
grid-template-rows: repeat(2, auto);
place-content: center end;
width: 150px;
height: 100px;
}
アイテム間の余白(ガター)
gap
プロパティを使用することで、アイテム間の余白(ガター)を調整することができます。gap
プロパティはコンテナに対して指定し、値は次のいずれかで指定します。
.container {
gap: 行列のアイテム間の余白;
gap: 行のアイテム間の余白 列のアイテム間の余白
}
次のコードは行のアイテム間の余白を30px、列のアイテム間の余白を10pxあてています。
.container {
display: grid;
grid-template-columns: repeat(3, auto);
grid-template-rows: repeat(2, auto);
gap: 30px 10px;
}
なおgap
プロパティは、行のアイテム間の余白としてrow-gap
プロパティ、列のアイテム間の余白としてcolumn-gap
プロパティのショートハンドでもあります。
.container {
display: grid;
grid-template-columns: repeat(3, auto);
grid-template-rows: repeat(2, auto);
row-gap: 30px;
column-gap: 10px;
}
自動配置の方向
grid-auto-flow
プロパティを使用することで、自動的にアイテムを配置する方法を指定することができます。grid-auto-flow
プロパティはコンテナに対して指定し、値は次のいずれかで指定します。
値 | 説明 |
---|---|
row |
水平(Z字型)方向へ配置します。初期値です。 |
column |
垂直(N字型)方向へ配置します。 |
dense |
空間を埋めます。 |
row dense |
水平(Z字型)方向かつ空間を埋めます。 |
column dense |
垂直(逆N字型)方向かつ空間を埋めます。 |
.container {
display: grid;
grid-template-columns: repeat(3, auto);
grid-template-rows: repeat(3, auto);
grid-auto-flow: column;
}
暗黙的に生成されたトラックの大きさを設定
grid-auto-rows
プロパティまたはgrid-auto-columns
プロパティを使用することで、暗黙的に生成されたトラックの大きさを設定することができます。コンテナに対して指定します。次の例では行に対して幅を50pxに固定しています。
.container {
display: grid;
grid-template-columns: repeat(3, auto);
grid-template-rows: auto;
grid-auto-rows: 50px;
}
配置の定義を一括で指定
grid-template
プロパティはgrid-template-area
プロパティ、grid-template-rows
プロパティ、grid-template-columns
プロパティを一括で指定できるショートハンドです。例えば次のように置き換えることができます。
各プロパティによる指定:
.container {
display: grid;
grid-template-areas:
"header header"
"main side"
"footer side";
grid-template-columns: 1fr 200px;
grid-template-rows: 50px 1fr auto;
}
grid-templateプロパティによる一括指定:
.container {
display: grid;
grid-template:
"header header" 50px
"main side" 1fr
"footer side" auto / 1fr 200px;
}
暗黙的な行列の分割(生成)
グリッドレイアウトは暗黙的に行または列を分割(生成)する機能があります。アイテムの配置と任意に指定しなければ、配置する方向に沿ってアイテムを自動的に並べていきます。このとき、例えば列だけ分割数を設定した場合、アイテムが列の数を超えた場合、自動的に次の行を生成し、その生成した行にアイテムを配置していきます。
<div class="container">
<div class="item">A</div>
<div class="item">B</div>
<div class="item">C</div>
<div class="item">D</div>
<div class="item">E</div>
<div class="item">F</div>
<div class="item">G</div>
</div>
.container {
display: grid;
grid-template-columns: repeat(3, auto);
grid-template-rows: auto;
}
応用編
グリッドシステム(レイアウトグリッド)
応用というわけではないですが、BootstrapなどのCSSフレームワークにもあります、グリッドシステムとして使用することができます。プロトタイピングツールなどデザインではレイアウトグリッドと同じ使い方が可能です。
.container {
display: grid;
grid-template-columns: repeat(12, auto);
gap: 10px;
}
.item {
background-color: #eee;
}
.item.col-4 {
grid-column-start: span 4;
}
.item.col-8 {
grid-column-start: span 8;
}
<div class="container">
<div class="item col-4">A</div>
<div class="item col-8">B</div>
</div>
レイヤー数の少ない表組みや定義リストなどの縦ぞろえ
定義リストでdt要素とdd要素が水平方向に並び、この1セットを垂直方向に並ぶような実装を行うときにグリッドレイアウトが役立ちます。例えば次の例では、フォームの項目名と入力欄が垂直方向にそろったように並びます。
<dl class="list">
<dt><label for="name">お名前</label></dt>
<dt><input name="name" id="name"></dt>
<dt><label for="mail_address">メールアドレス</label></dt>
<dt><input name="mail_address" id="mail_address"></dt>
<dt><label for="content">お問い合わせ内容</label></dt>
<dt><textarea name="content" id="content"></textarea></dt>
</dl>
.list {
display: grid;
grid-template-columns: auto 1fr;
gap: 10px;
}
grid-template-rows
プロパティを指定しなくても暗黙的に行を生成してくれますで、行が増えても問題なく配置されます。
水平方向に並んでいるパーツの中の要素の高さをそろえる
カード型コンポーネントなど、水平方向に並んでいるパーツで、それぞれの中の要素の垂直方向の位置をそろえる場合、CSSだけではなかなか実装が難しいことがあります。実装しようとしますと、テーブルレイアウトで組むか、高さを完全に固定するか、JavaScriptを用いて同じ水平方向の要素の最大の高さに合わせて高さを固定するといった方法で実装する必要があります。
そこで、グリッドレイアウトのサブグリッドという機能を使用しますと、簡単に実装することができます。
<div class="cards">
<div class="card">
<img src="xxx.png" width="208" height="117" alt="">
<p class="title">タイトルタイトルタイトルタイトルタイトルタイトルタイトルタイトルタイトル</p>
<p class="detail">説明文章説明文章説明文章説明文章説明文章説明文章説明文章説明文章説明文章説明文章</p>
<a href="xxx">詳細ページへ</a>
</div>
<div class="card">
<img src="xxx.png" width="208" height="117" alt="">
<p class="title">タイトルタイトルタイトルタイトル</p>
<p class="detail">説明文章説明文章説明文章説明文章説明文章説明文章</p>
<a href="xxx">詳細ページへ</a>
</div>
<div class="card">
<img src="xxx.png" width="208" height="117" alt="">
<p class="title">タイトル</p>
<p class="detail">説明文章説明文章説明文章説明文章説明文章説明文章説明文章説明文章説明文章説明文章説明文章説明文章説明文章説明文章</p>
<a href="xxx">詳細ページへ</a>
</div>
</div>
.cards {
display: grid;
grid-template-columns: repeat(3, 208px);
grid-template-rows: repeat(4, auto);
column-gap: 20px;
}
.card {
display: grid;
grid-template-rows: subgrid;
grid-row: span 4;
}
また、サブグリッドは階層が深くてもサブグリッドとして扱うことができます。
<div class="cards">
<div class="card">
<img src="xxx.png" width="208" height="117" alt="">
<div class="text">
<p class="title">タイトルタイトルタイトルタイトルタイトルタイトルタイトルタイトルタイトル</p>
<p class="detail">説明文章説明文章説明文章説明文章説明文章説明文章説明文章説明文章説明文章説明文章</p>
</div>
<a href="xxx">詳細ページへ</a>
</div>
<div class="card">
<img src="xxx.png" width="208" height="117" alt="">
<div class="text">
<p class="title">タイトルタイトルタイトルタイトル</p>
<p class="detail">説明文章説明文章説明文章説明文章説明文章説明文章</p>
</div>
<a href="xxx">詳細ページへ</a>
</div>
<div class="card">
<img src="xxx.png" width="208" height="117" alt="">
<div class="text">
<p class="title">タイトル</p>
<p class="detail">説明文章説明文章説明文章説明文章説明文章説明文章説明文章説明文章説明文章説明文章説明文章説明文章説明文章説明文章</p>
</div>
<a href="xxx">詳細ページへ</a>
</div>
</div>
.cards {
display: grid;
grid-template-columns: repeat(3, 208px);
grid-template-rows: repeat(4, auto);
column-gap: 20px;
}
.card {
display: grid;
grid-template-rows: subgrid;
grid-row: span 4;
}
.card .text {
display: grid;
grid-template-rows: subgrid;
grid-row: 2 / span 2;
}
ただし、サブグリッドについてはFirefoxは比較的前のバージョンから対応されていましたが、それ以外のブラウザーは最近実装したばかりだったり、そもそも対応していなかったりと標準で実装するには難しいかもしれません。詳しい対応ブラウザーとバージョンについては次のページをご覧ください。https://caniuse.com/css-subgrid
なお、アイテムにdisplay: contents
を指定することでも同じようなことを実装することは可能です。こちらはアイテムが自動的に配置される(流れる)方向を変えてあげる必要があります。また、アイテムのボックスモデルがコンテンツだけになりますので、アイテムでのmarginプロパティやborderプロパティなど、コンテンツ以外の調整を行うことはできなくなります。
.cards {
display: grid;
grid-template-columns: repeat(3, 208px);
grid-template-rows: repeat(4, auto);
grid-auto-flow: column;
column-gap: 20px;
}
.card {
display: contents;
}