flexboxでjustify-content: space-betweenを設定していると
最後の行のアイテムが左と右に寄っちゃう…
flexboxのjustify-contentは「フレックスコンテナの中身の配置方法を指定する」ためのプロパティです。
space-betweenという値を指定すると、「アイテムが横方向に均等に配置され、それぞれの行の先頭のアイテムは左寄せ、最後のアイテムは右寄せ」になります。
なんといっても、アイテム間のmarginが均等になるように
自動で調整してくれるのがjustify-content:space-betweenの便利なところ。
ですが…
たとえば、3列・4列のflexboxでjustify-content: space-betweenを指定し、かつ最後の行のアイテム数が2つの場合は下図のようになってしまいます。
点線で示しているのは、アイテムがないところです。
このように普通は最後の行にある2つのアイテムが左右に寄ってしまいます。
この記事では、3列・4列のflexboxでjustify-content: space-betweenを指定しても、下図のように最後の行を左寄せにできる方法をご紹介します。
3列の場合のCSS例
まず、3列の場合からです。
先にCSSを記載しておきます。
もちろんclass名はお好みの名前にしてくださいね。
それから、今回のテクニックに必要なスタイル以外は記載していません。
/* 親要素 */ .parent-col3 { display: flex; flex-wrap: wrap; /* 折返し可 */ justify-content: space-between; } /* 子要素 */ .child { width: 28% ; /* 親要素の1/3より小さい値 */ } /* 親要素の疑似要素 */ .parent-col3::after { content: ""; display:block; width:28%; /* 子要素と同じ幅 */ }
.parent-col3::after は親要素(.parent)内の最後の疑似要素となります。
幅は子要素と同じ値にしておきましょう。
これだけで本当になるの?と思いますよね。
デモをおいときますので、併せてご覧ください。
ここからは、デモのスクリーンショットを使って解説します。
最後の行のアイテム数が3の場合
「最後の行のアイテム数が3」の場合、つまりそもそも最後の行がきれいに並んでいる場合ですが、疑似要素(::after)はその次の行の左に入ります。
ただし、疑似要素は高さを持たせていないため、疑似要素がここに来た場合でもレイアウトには影響を及ぼしません。
最後の行のアイテム数が2の場合
つぎに、「最後の行のアイテム数が2」の場合です。
これが、もともと問題がある(最後の行が左右に寄る)ケースでしたね。
この場合、疑似要素は最後の行の右端に入ることで、結果的に本来の最後のアイテム(.child)が左に詰まり、期待通りの結果となります。
最後の行のアイテム数が1の場合
そして、「最後の行のアイテム数が1」の場合はこのようになります。
これはもともと問題ないケースですので、説明は要らないと思います。
このように、疑似要素を使うことで、3列の場合はどのケースでも最後の行のアイテムを左に詰めることができることが分かりました。
4列の場合のCSS例
では、つぎに4列の場合です。
こちらも先にCSSを記載しておきますね。
/* 親要素 */ .parent-col4 { display: flex; flex-wrap: wrap; /* 折返し可 */ justify-content: space-between; } /* 子要素 */ .child { width: 23% ; /* 親要素の1/4より小さい値 */ } /* 親要素の疑似要素 */ .parent-col4::after { content: ""; display:block; width:23%; /* 子要素と同じ幅 */ } .parent-col4::before { content: ""; display:block; width:23%; /* 子要素と同じ幅 */ order: 1; /* アイテムの並び順 */ }
.parent-col4::after と.parent-col4::before は親要素(.parent)内の最後の2つの疑似要素となります。
いずれも幅は子要素と同じ値にしておきましょう。
さっきとほとんど一緒ですが、
疑似要素の::beforeも使います。
もう一度デモを見てみましょう。
ここからは、デモのスクリーンショットを使って解説しますが、その前に。
order:1 とは?
上記のCSSサンプルにあった「.parent-col4::before」セレクタで「order:1」というスタイルが指定されています。
order:1って何をやってるの?
orderは、flexboxのアイテムの並び順を指定するためのプロパティです。
「order:1」ということは、「.parent-col4::before」が1番目ということになりますが、orderが指定されていないアイテムは0番目となります。
つまり、「.parent-col4::before」は最後であり、
「.parent-col4::after」の次に並ぶということになります。
最後の行のアイテム数が4の場合
まず、「最後の行のアイテム数が4」の場合(そもそも最後の行がきれいに並んでいる場合)ですが、::afterは最後の行の左、::beforeは最後の行の右に入ります。
この場合も、疑似要素は高さを持たせていないため、レイアウトには影響を及ぼしません。
最後の行のアイテム数が3の場合
「最後の行のアイテム数が3」の場合は、::afterが右端に配置されるため、本来の子要素3つがきちんと左に詰まります。
::beforeは折り返したあとの次の行の左端に来ますが、これも実際は見えない(高さがない)ため、レイアウトに問題はありません。
最後の行のアイテム数が2の場合
「最後の行のアイテム数が2」の場合は、この記事の最初のほうでお見せした画像と同じケースですが、最後の行の3つめに::afterが、4つめに::beforeが入り、子要素(.child)2つは左に詰まります。
最後の行のアイテム数が1の場合
そして最後に「最後の行のアイテム数が1」の場合は、::afterと::beforeが入っても最後の行の要素は3つとなります。
::afterが中央に、::beforeが右端に入りますが、この場合はそもそも疑似要素がなくても問題がないケースでした。
疑似要素をうまく使えば、justify-content: space-between でも最後の行を左寄せにできる(ただし3列と4列の場合のみ)
今回ご紹介したのは3列または4列の場合にCSSだけでできる対処法です。
最後の行のアイテムがどんな数の場合でも対応できることが分かりました。
5行以上になると、CSSのみでの対処は難しく
javascriptなどを使う必要があるようです。
これで、もっと気軽に「justify-content: space-between」を使うことができるのではないでしょうか。