グリッドでよこ並び

CSSの「グリッドレイアウト」は、要素の中身を格子状に分割してできたマス目フィールドに子要素を好なように配置することができるレイアウトモデルです。displayプロパティにgridという値を指定することで利用できます。そんなグリッドレイアウトを使って、よこ並びしてゆきます!

グリッドは自由

フレックスボックスレイアウトは一次元のレイアウトモデルでしたが、グリッドレイアウトは「二次元」のレイアウトモデルって言われます。つまり縦にも横にも自由にレイアウトする事ができるということ。縦線と横線で区切った格子状のマス目に、任意の要素を割り当てていく感覚で、画面をレイアウトしてゆくことができます。なのできっと「よこ並び」だけじゃ役不足かもしれませんね…

ナビゲーションをよこ並び

まずは早速、例のナビゲーションにグリッドレイアウトを適用してみましょう!
ul要素にdisplayプロパティgridを指定します。リンクボタンの隙間は、フレックスボックスの時と同じgapプロパティが使えます:)

.nav_list {
	display: grid;
	gap: 1px;
}

あれれ、隙間は空いたけど、縦に並んだままですね…:‹。フレックスボックスはデフォルトがよこ並びだったけれど、グリッドはデフォルトがたて並びになるんですねぇ:o
グリッドをよこ並びになるようにするには、ul要素にさらにgrid-auto-flowプロパティで、columnと指定します。

.nav_list {
	display: grid;
	gap: 1px;
	grid-auto-flow: column;
}

もしくは、grid-template-columnsプロパティを使って、横方向にリンクボタンの数だけマス目を用意することもできます。ここでは、li要素が5つ横に並ぶように、autoという値を5つ並べて指定します。

.nav_list {
	display: grid;
	gap: 1px;
	grid-template-columns: auto auto auto auto auto;
}

グリッドレイアウトの基本概念

displayプロパティでgridと指定した要素は「グリッドコンテナー」、その直接の子要素は「グリッドアイテム」という状態になります。
そして、コンテナー内に暗黙的に、下図のような格子状の体系システムを形成します。

要素を分割するグリッドラインと、その線に囲われてできたグリッドセルから構成される、レイアウトの骨格となる“グリッド”が用意されます:)
要素とはに、レイアウトするための空間が用意されて、そこにグリッドアイテムを配置していくっていう仕組みなんです。つまり「グリッドを用意して、要素を配置する」っていうのが、グリッドレイアウトの一連の流れになります。:)

グリッドの用意

グリッドレイアウトを適用すると、まず最初に、自動配置ルールに従って暗黙的にグリッドが用意され、「行が埋まったら新しい行」という具合にグリッドアイテムを配置してゆきます。
上のサンプルでは、それを、grid-auto-flowプロパティcolumnと指定することで、「列が埋まったら新しい列」という流れ方に変えていたんですねー。
この状態で、要素がひとつ増えると、6つめの要素アイテム新しい列へ配置されます。

一方、grid-template-columnsプロパティでは、明示的にグリッドを用意します。行に5列用意したことで、下図のような流れ方になっていたってわけ;)
なので要素がひとつ増えると、6つめの要素は新しい行の最初の列へ配置されます。

要素アイテムの配置

グリッドアイテムは、デフォルトでは、自動配置ルールに従って、暗黙的に(順に)配置されてゆきますが、grid-columnプロパティを使って、明示的に配置することができます。
配置するグリッドの位置は、グリッド線の番号でもって指定します。
例えば下図のように、2つめの要素は「2番めと4番めの線」に挟まれた列に配置し、3の倍数の要素は「5番めと6番めの線」に挟まれた列に配置する、という具合。

CSSでは、「2番めと4番め」なら2 / 4という風に、始めの線終わりの線/スラッシュで区切って指定します。こんな妙ちくりんなレイアウトも、グリッドレイアウトならば朝飯前なのです:D

.nav_list li:nth-child(2) {
	grid-column: 2 / 4;
}
.nav_list li:nth-child(3n) {
	grid-column: 5 / 6;
}

グリッドレイアウトについて、詳しくは下記ページを参照のこと。
グリッドレイアウトの基本概念 - CSS: カスケーディングスタイルシート | MDN

中央に配置する

フレックスボックスの時と同じように、justify-contentプロパティが使えます。centerと指定すれば、アイテムがコンテナーの左右中央に寄せて配置されます。
※grid-template-columnsプロパティでよこ並びした方も同じ。

.nav_list {
	display: grid;
	gap: 1px;
	grid-auto-flow: column;
	justify-content: center;
}

リンクボタンのサイズを揃える

グリッドレイアウトでは、アイテムの横幅もコンテナー側に指定します。grid-auto-flowプロパティでよこ並びにした方は、grid-auto-columnsプロパティを使ってアイテムの幅を指定できます。ここでは、フレックスボックスの時と同じように、12emと指定します。

.nav_list {
	display: grid;
	gap: 1px;
	grid-auto-flow: column;
	grid-auto-columns: 12em;
	justify-content: center;
}

grid-template-columnsプロパティでよこ並びにしている方は、autoとしていた値を、すべて12emに書き換えます。けど、同じ値を何個も並べて書くのはなんだか冗長ですね…:‹
こんな時はrepeat()関数が使えます。括弧の中に繰り返す回数と、繰り返す値をカンマ区切りで指定します。ここでは「12emを5回繰り返す」ので、以下のように書けます:)

.nav_list {
	display: grid;
	gap: 1px;
	grid-template-columns: repeat(5, 12em);
	justify-content: center;
}

リンクボタンの高さも、フレックスボックスの時と同じ要領で揃える事ができます。a要素の高さをli要素いっぱいに広げつつ、グリッドレイアウトを適用して、中のテキストを上下中央に配置します。
※grid-template-columnsプロパティの方も同じ。

.nav_list a {
	display: grid;
	align-items: center;
	height: 100%;
	box-sizing: border-box;
}

レスポンシブにする

スマホではたて並びになるよう、メディアクエリを使って、768px以上の時だけよこ並びになるようにします。前述までのよこ並びにするためのスタイルを、メディアクエリの中に移動しちゃえばOKです:D

.nav_list {
	display: grid;
	gap: 1px;
}
@media screen and (min-width: 768px) {
	.nav_list {
		grid-auto-flow: column;
		justify-content: center;
		grid-auto-columns: 12em;
	}
	.nav_list a {
		display: grid;
		align-items: center;
		height: 100%;
		box-sizing: border-box;
	}
}

ありゃ、768px以上の時に左右にハミ出ちゃってます…。リンクボタンが伸縮せずに、12emのサイズに固定されてるみたいです:(
フレックスボックスのflex-basisプロパティはあくまで基準となるサイズだから、固定されずにコンテナーに合わせて伸縮していたけれど、grid-auto-columnsプロパティで指定したサイズは、それとは違うんですね…:(
グリッドコンテナーに合わせて伸縮するように、min()関数を使って、以下のように指定し直します。

@media screen and (min-width: 768px) {
	.nav_list {
		grid-auto-flow: column;
		justify-content: center;
		grid-auto-columns: min(20%, 12em);
	}
	⋮

伸縮するようになりましたね!
けど、よぉ〜く見てみると、ナビゲーションの横幅が若干、nav要素よりもハミ出てるように見えます…¦‹。どうやらgapプロパティで指定している隙間1pxが、リンクボタンの横幅20%含まれていないみたい…⁑|フロートの時にも同じような事があったけれど、今回はパディングは使ってないので、box-sizingプロパティでは解決できなそう…。

100%から隙間4つ分の幅(4px)を引かなきゃいけないわけだから…、リンクボタンの横幅は、20%から4pxを5等分した幅を引けば良いって事。CSSで書くとcalc(20% - 4px / 5)という事になります。

min()関数の中でも、calc()関数と同じように計算式を使う事ができるので、以下のように指定できます。

@media screen and (min-width: 768px) {
	.nav_list {
		grid-auto-flow: column;
		justify-content: center;
		grid-auto-columns: min(20% - 4px / 5, 12em);
	}
	⋮

ナビゲーションが綺麗に収まりました:D

frという単位

リンクボタンの幅に1frという値を使うことで、もっとシンプルに解決できます。frとは、グリッドレイアウトだけで使える単位。グリッドアイテムのサイズをコンテナー内のサイズの比率って指定できます。frは「fraction(分数)」の略。
ここでは、12emとしていたところを、1frに置き換えます。それだけだとナビゲーションがビューポートいっぱいに広がっちゃうので、ナビゲーションの横幅を制限して、左右にマージンautoを指定して中央に配置します。

ナビゲーションの横幅は、「リンクボタンの幅を12emと指定してた時」と同じ幅になるように、calc(60em + 4px)という横幅にしてます。

@media screen and (min-width: 768px) {
	.nav_list {
		max-width: calc(60em + 4px);
		margin-inline: auto;
	}
	.nav_list.-auto {
		grid-auto-flow: column;
		grid-auto-columns: 1fr;
	}
	.nav_list.-template {
		grid-template-columns: repeat(5, 1fr);
	}
	⋮
}

横幅の値が20%だと、隙間分の誤差が出ちゃってましたが、1frなら、隙間分も考慮して、要素の幅を分割するので、ちょいハミの心配もありません:)


比率で分割する」というと、フレックスボックスのflex-growプロパティにも似ているけれど、flex-growプロパティは余白を分配するのに対して、fr単位要素自体のサイズを比率で分割するので、ちょっと違います。
flex-basisプロパティの値を0に指定して、コンテナーの横幅すべてが余白になれば、同じ結果になるんですけどね;p(下サンプル下段)

.nav_list.-grid {
	grid-template-columns: 1fr 2fr 1fr 1fr 1fr;
}
.nav_list.-flex li {
	flex-grow: 1;
	flex-basis: 0;
}
.nav_list.-flex li:nth-child(2) {
	flex-grow: 2;
}

グリッドレイアウトで商品一覧

ナビゲーションは、一方向だけのレイアウトだったので、そういうレイアウトならフレックスボックスの方がもっとシンプルにできた気がしますね…:3グリッドでも出来ないことはないけど、勿体ない感じがします。
かたや、商品一覧のような縦と横に並ぶレイアウトこそ、グリッドレイアウトの腕の見せ所なのです。:)

グリッドで商品一覧

商品一覧にもグリッドレイアウトを適用します!
横3列に並ぶ一覧なので、ここではgrid-template-columnsプロパティで、明示的に3列のグリッドを用意する作戦でいきます。横幅はグリッド専用の1frという値で、均等に配置します。
li要素にパディングを指定しているけれど、横幅の指定はないのでbox-sizing: border-boxの指定は要らないです。

.menu_list {
	display: grid;
	grid-remplate-columns: repeat(3, 1fr);
	max-width: 1024px;
	margin: 0 auto;
}
.menu_list li {
	padding: 16px 32px;
}

きれーいに、かんたーんにレイアウトできちゃいましたXD

レスポンシブにする

他の記事と同じく、メディアクエリを使って、429px以上の時は2列、768px以上の時は3列になるように調整します。と言ってもとってもシンプル。grid-template-columnsプロパティ繰り返す回数の値を、23と増やすだけです。

@media screen and (min-width: 429px) {
	.menu_list {
		grid-template-columns: repeat(2, 1fr);
	}
}
@media screen and (min-width: 768px) {
	.menu_list {
		grid-template-columns: repeat(3, 1fr);
	}
}

グリッドレイアウトだけの特別な値を使えば、メディアクエリを使わずに、一覧の列数を切り替えることもできます。
repeat()関数繰り返す回数の指定に、auto-fitという値を指定して、横幅には3列ちょうど収まるようにcalc(1024px / 3)と指定。auto-fitは、アイテムがコンテナーに収まる数として適用されます。

.menu_list {
	display: grid;
	grid-template-columns: repeat(auto-fit, calc(1024px / 3));
	justify-content: center;
	max-width: 1024px;
	margin-inline: auto;
}