フロートでよこ並び

そのむかし、よこ並びCSSといえばfloatプロパティでした。よこ並びといえば、ほぼfloatプロパティだけでまかなっていましたよね。現在はよこ並びとして使うのは忌まわれがちなfloatプロパティですが、フレックスボックスレイアウトやグリッドレイアウトとは違う、特殊なよこ並びの手法のひとつとして、覚えておいても良いんじゃないかなと思います。

フロートでのレイアウト

floatプロパティは本来、よこ並びするためのプロパティではなく、特定の要素を左右に寄せて配置するためのプロパティです。
例えば、下のサンプルみたく、文章中の挿絵をレイアウトする時。img要素に対してfloat: leftと指定すれば、画像は左側に寄り、float: rightと指定すれば、画像は右側に寄り、その後に続く要素は、画像を避けながら、その隣に回り込むようにレイアウトされます。

フロートでのよこ並び

そんなfloatプロパティを使って要素をよこ並びにしてみます。
例えば下のサンプルのようなナビゲーションならば、li要素すべてにfloat: leftを指定して、続々と左へ寄せることで、横一列に並べることができます。横幅を指定しなければ、その要素の内容(ここでは文字数)に準拠した横幅でよこ並びになります。
また、ふたつめ以降のli要素li:nth-child(n+2)の左側に1pxのパディングを指定して、ボタンごとに隙間を空けています。

.nav_list li {
	float: left;
}
.nav_list li:nth-child(n+2) {
	padding-left: 1px;
}

フロートしたら解除が必要

※フロートした後には、フロート解除も忘れずに。ここでは、.nav_list::after擬似要素に、clearfixを適用しています。

.nav_list::after {
	content: "";
	display: block;
	clear: both;
}

clearfixについては下記ページを参照のこと。
clear - CSS: カスケーディングスタイルシート | MDN

ナビゲーションを中央に配置する

上のサンプルだと、ナビゲーション全体が左に寄っちゃってますけれど、中央に配置したいなって時には、ul要素の横幅にfit-contentという値を指定して、左右のマージンにautoを適用すれば、うまく中央に配置されます。
fit-contentは、指定した要素内のコンテンツに準拠したサイズを表すキーワードで、ここでは、li要素5つ分の横幅が、ul要素に適用されます。そして幅を持つプロック要素は、左右のマージンにautoが適用されると、うまい具合に中央に寄るのです。:)

.nav_list {
	width: fit-content;
	margin-inline: auto;
}

ナビゲーションを横幅いっぱいにレイアウトする

ナビゲーション全体を親要素の横幅いっぱいに広げるには、widthプロパティの値の合計が100%となるように、li要素の横幅に20%を指定します。

.nav_list li {
	float: left;
	width: 20%;
}

あれれ、なんだか変になっちゃいました。最後のリンクボタンが改行しちゃってるみたいですね…:(
width/heightプロパティで指定したサイズは、paddingプロパティの内側のサイズとして適用されて、paddingプロパティの値は指定したサイズの外に適用されるんです。
つまり今、リンクボタンの横幅は、20% + 1pxになってるってこと。100%を超えて、最後のひとつだけ改行しちゃいました。Xp

この振る舞いは、box-sizingプロパティで変更できます。
デフォルトではcontent-boxという値になっていて、width/heightプロパティで指定したサイズは、padding/borderプロパティの値を含まないサイズとして適用されるのだけれど、これをborder-boxという値に変えると、padding/borderプロパティの値を含むサイズとして適用されるようになります。
レイアウトする時にはこちらの振る舞いの方がわかりやすくて良いですね:)

.nav_list li {
	float: left;
	width: 20%;
	box-sizing: border-box;
}

均等に横に並んだけれど、文字数によって改行されると、リンクボタンの高さが揃わなくてかっこ悪いです…。
下のサンプルでは、リンクボタンのテキストがなるべく1行になるように、文字数に合わせてボタンの横幅を調整してみたけれど、画面幅によっては結局、改行したりしなかったりするし…X(

.nav_list li {
	float: left;
	width: 17%;
	box-sizing: border-box;
}
.nav_list li:nth-child(2) {
	width: 36%;
}
.nav_list li:nth-child(3),
.nav_list li:nth-child(5) {
	width: 15%;
}

文字数をうかがいながら細かい調整するのは、面倒臭いから、ちょっとかも…。
そんな時にはテーブルレイアウトを使う方法が便利です!…けれどそれはまた次の記事で。

フロートで商品一覧

商品一覧は横3列になるので、ひとつの商品の横幅を、全体の33.333%に指定して、それぞれにfloat: leftを指定します。隣の商品との間隔をとるために、商品の周囲にパディングを指定しておきます。widthプロパティとpaddingプロパティを併用しているので、box-sizingプロパティborder-boxにしておくのが良いですね:D
商品一覧自体は最大幅を1024pxにして、左右にマージンautoを指定して中央に配置されるようにします。あと、clearfixも忘れずに適用しておきます。

.menu_list {
	max-width: 1024px;
	margin: 0 auto;
}
.menu_list li {
	float: left;
	width: 33.333%;
	padding: 16px 24px;
	box-sizing: border-box;
}
.menu_list::after {
	content: "";
	display: block;
	clear: left;
}

3つずつ並んで2段になるはずが、4つめの商品が真ん中に配置されちゃって、グチャグチャになっちゃいました…X(
フロートした要素の後に続く要素は、フロートした要素の隣へ隣へと並びたがるので、ちょっとでも隣に並べそうな隙間があるとそこへ並んじゃうんです…。最初の商品が、あとの2つの商品よりも文章量が多くて縦に長い分できた段差に、4つめの商品が引っ掛かっちゃってる様子ですね。

これを正すために、clearプロパティを使います。clearプロパティを指定した要素は、先行する要素の隣に並ぼうとしなくなるんです。
たとえば、clear: leftと指定した要素は、先行する要素が左へフロートしていても、それに影響されることなく次の段へ配置されるということ。
3列に並んでるので、改行しなきゃならん要素は、“3つめの次”。これを:nth-child擬似クラスを使って下図のように表します。

3つめの次=li:nth-child(3n+1)で指定できる
.menu_list li:nth-child(3n+1) {
	clear: left;
}

綺麗に並びました!
けど、スマホで見ている人は気づいてしまっているかもしれませんが、画面の横幅が狭い時に、商品がすんごい小さくなってしまってます…⁑|。横幅が狭くなったら横の列数を少なくなるようにしたいですね、そう、レスポンシブに!:D

レスポンシブにする

レスポンシブ(Responsive)は“反応する”という意味。レスポンシブWebデザインというと、Webサイトを閲覧している環境や、表示領域ビューポートサイズに応じて、適したデザインで閲覧できるように調整されたWebデザインのことを言います。
このサンプルみたいなレイアウトの商品一覧の場合には、横幅に合わせて並べる列数を切り替えて調整することが多いです。

レスポンシブに表示を切り替えるにはメディアクエリを利用します。@mediaルールという構文を使って、スタイルが適用される時のビューポート幅を制限することで、ビューポート幅に合わせて、スタイルを切り替えることができるようになります。
ここでは、767px以下の時は2列、428px以下の時には1列になるようにします

767px以下とはつまりiPad未満(iPadを含まない、それよりも小さいビューポート幅)ということ。428pxはちょうどiPhone 14 Pro Maxを縦に持った時のビューポート幅になります。

@media (max-width: 767px) {
	.menu_list li {
		width: 50%;
	}
}
@media (max-width: 428px) {
	.menu_list li {
		width: 100%;
	}
}

2列の時にまたグチャッちゃいました…。2列ずつになって改行位置が変わったので、clearする要素を変えねばなりません。今度は、“2つめの次”にclearプロパティを適用します。“3つめの次”に指定してたclearプロパティは、noneに指定し直しておきます。
1列の時には、“2つめの次”のclearプロパティもnoneと指定しておきましょう。
フロートで商品一覧は一丁あがり!

@media screen and (max-width: 767px) {
	.menu_list li {
		width: 50%;
	}
	.menu_list li:nth-child(3n+1) {
		clear: none;
	}
	.menu_list li:nth-child(2n+1) {
		clear: left;
	}
}
@media screen and (max-width: 428px) {
	.menu_list li {
		float: none;
		width: 100%;
	}
	.menu_list li:nth-child(2n+1) {
		clear: none;
	}
}

メディアクエリについて、詳しくは下記ページを参照のこと。
メディアクエリの利用 - CSS: カスケーディングスタイルシート | MDN

効率的に指定する

とはいえ、上の指定方法だと、clearプロパティの値を上書きに上書きを重ねてて、ちょっと要領が悪い気がしますね:(。本当に指定が必要なところだけ指定するようにすれば、もっと効率的になるはず!

まずフロートするのは429px以上の時だけです。それから、3分割するのは768px以上の時だけだし、2分割するのは767px〜429pxの間だけですね。それらを鑑みてメディアクエリを指定すると、以下のようになりました。

.menu_list li {
	padding: 16px 24px;
	box-sizing: border-box;
}
@media screen and (min-width: 429px) {
	.menu_list li {
		float: left;
		width: 50%;
	}
	.menu_list::after {
		content: "";
		display: block;
		clear: left;
	}
}
@media screen and (min-width: 429px) and (max-width: 767px) {
	.menu_list li:nth-child(2n+1) {
		clear: left;
	}
}
@media screen and (min-width: 768px) {
	.menu_list li {
		width: 33.333%;
	}
	.menu_list li:nth-child(3n+1) {
		clear: left;
	}
}

さっきは「〜以下の時は」という指定の仕方だったので、「767px以下428px以下」の順(幅が広い方から狭い方の順)に指定してました。けれども今度は「〜以上の時は」という指定の仕方になってるので、「429px以上768px以上」の順(幅が狭い方から広い方の順)に指定してる点に注意です:o

テーブルレイアウトでよこ並び