display: flexで、高さを統一しているときに、特定要素のみ高さをフリーにする

ホームページ制作をしていると、2列構成や3列構成にすることもしばしばあります。
以前ならfloat指定でカラムを構成していました。
ですが、最近ではdisplay:flexなるスタイルシートが増え、おもったより簡単に列構成レイアウトができるようになりました。
display:flexは、floatと異なり、「高さ」が存在します。
それゆえ、複雑な構造もレイアウトできます。
例えば3列2行構成の場合、align-items: flex-start;指定をすれば、同一行で同じ高さに揃えられます。
ですが、レイアウト上次のようなことをする必要がありました。
特定のboxだけ、高さをフリーにする。
全部高さをそろえる、全部フリーにするは簡単にできます。
align-items: flex-start;を指定する、しないで済むからです。
ですが、他のboxは高さをそろえ、特定の1個だけ高さをフリーにすることなんてできるの?
半信半疑でしたが、やってみたらできました。
忘備録として記録いたします。
やりたいことは次の通りです。

全部で6つのboxがあり、それぞれ行ごとに高さが揃うようにしています。
実際は1行分しかいないboxも2行分の高さになっています。
ですが、4個目のboxのみ高さを他のboxに引きずられることなく、高さを自由にしたいのです。
できてしまえばあっけないものですが、その理屈がわかるまで少し手間取りました。
なぜならばflex指定には、多くのオプション指定があるからです。
それがflexの使い方を分かりにくくしている部分でもあります。
まず最初にやってみたのがこちら

まずは以下のようなコーディングをしてみました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | <!doctype html> <html> <head> <meta charset="shift_jis"> <title>無題ドキュメント</title> <style type="text/css"> .box { width:1000px; margin-right:auto; margin-left:auto; } ul { display:flex; justify-content:space-between; gap:30px; padding-right:60px; align-items:stretch; flex-wrap:wrap; } ul li { display:block; border:1pxsolid#000; width:30%; text-align:center; } </style> </head> <body> <div class="box"> <ul> <li>1<br>改行</li> <li>2</li> <li>3</li> <li>4</li> <li>5<br>改行</li> <li>6</li> </ul> </div> </body> </html> |
ulにflex指定をして、align-items: stretch;指定で高さをそろえています。

当然ですが、高さが揃います。
4番だけ高さをフリーにしたいのですが、これではだめです。
高さそろえをしないとこうなりました。

ならばと、align-items: flex-start;指定をなしにしたところ、4番以外のboxの高さもフリーになりました。

基本は、box同士で高さを揃えたいため、align-items: flex-start;指定は必須です。
ではどうすればよいのでしょうか?
個別指定で高さ揃えをキャンセルする

要は、4番目のliタグだけ、高さ揃えをキャンセルできればOKなのです。
そんな都合の良い指定ができるのか?
と思いましたが、ちゃんと用意されていました。
それがこちらの記述です。
1 2 3 4 | ul li:nth-of-type(4) { align-self:flex-start; } |
意味合い的には、liタグの4番目だけ、高さ揃えを初期値(上揃え)にするという意味です。
上揃えなのでstretchと違い、高さがフリーになります。
ここで疑問がわきました。
:nth-of-type(4)指定と同じようなものに、:nth-child(4)があります。
今回の例だと、どちらを指定しても、同じ結果になります。
では、違いは何だろう?
ついでに調べてみました。
:nth-of-typeと:nth-childの違い。

どちらも子要素の何個目を指定するものです。
ulタグ内のliタグを指定する場合等では、結果が同じになります。
ではなぜ、同じ動きをするものが2種類あるのか?
調べてみました。
:nth-childは子要素すべてを数えます
例えば以下の記述の場合、3コメのliタグを指定します。
1 2 3 4 5 6 7 8 9 10 11 12 | ul li:nth-child(4) { align-self:flex-start; } <ul> <li>1個目</li> <li>2個目</li> <div>divタグ</div> <li>3個目←これを示します</li> <li>4個目</li> </ul> |
そもそもulタグ内にdivタグを入れるのもおかしいとは思いますが、もし入っていた場合、1つの子要素としてカウントされます。
ちなみに、:nth-child(3)を指定したらどうなるのか試してみたところ、どれも選択されないという状態になりました。3番目はdivタグだけれども、liタグを指定しているので、選択されない。
:nth-of-typeは指定要素だけを数える
それに対し、:nth-of-typeは、指定要素だけを数えます。
以下の記述だと、4個目のliタグが選択されます。
1 2 3 4 5 6 7 8 9 10 11 12 | ul li:nth-of-type(4) { align-self:flex-start; } <ul> <li>1個目</li> <li>2個目</li> <div>divタグ</div> <li>3個目</li> <li>4個目←これを示します</li> </ul> |
:nth-of-typeは、指定したタグだけを数えます。
なので、:nth-childの場合は、3個目のliタグが指定されましたが、:nth-of-typeの場合は、divタグを飛ばして、4個目のliタグが指定されます。
レイアウトする要素タグがバラバラな場合は、:nth-child、レイアウト要素タグが統一されている場合は:nth-of-typeが良いのかもしれません。
思いもよらない解決方法の見出し方
今までは、ググって調べ、試してダメならまたググるを繰り返していました。
ですが今回は、AIを使って調べました。
AIは、想像もしなかった解法を示してくれるので、新たな発見をすることが多いです。
ただ、AIに指示された通りにやっても上手くいかないことも多いので、ググるとAI併用が良いのかもしれません。