最終更新日:
justify-content:space-betweenで折り返し時に両端に配置されちゃう問題
こんにちは。五平餅くんです。
justify-contentはflexboxの便利なcssプロパティですよね。
しかし、便利だといって毎回使いまくると、WordPressのテーマ作成時に穴にハマることがあります。
今回は、時に応じて使い分けるべしというお話です(反省の意味もこめて)。
目次
justify-contentとは?
justify-contentプロパティは、flexboxのプロパティです。
display:flexと同時に使用することで、効果が発揮されます。
僕が何千回と見ているCSSリファレンスでは、次のように説明されています。
justify-content …… コンテナ内全体の主軸方向(初期値では横方向)の揃え位置を指定する
親要素にdisplay:flexとjustify-content:〇〇を指定することで、
子要素を、どのように間隔を空けて横配置するか?
ということや、
左づめか、右づめか、左右中央よせか?
を決めることができます。
justify-contentの値(代表的なもの)
さて、実際にどのように指定するとどうなるのでしょうか。
justify-content:center
justify-content:centerは、子要素を中央に配置します。
<div id="content">
<div class="inner">
<div class="flex-justify-center">
<div class="flex-content">
justfy-content:centerだと子要素は左右中央よせになるよ
</div>
</div>
</div>
</div>
.inner {
max-width: 800px;
width: 97%;
margin: 0 auto;
background: skyblue;
}
.flex-justify-center {
display: flex;
justify-content: center;
}
.flex-content {
padding: 10px;
background: #f5f5f5;
}
このコードは、このように表示されます↓
justify-content:flex-start
justify-content:flex-startは、子要素を左によせて配置します。
<div id="content">
<div class="inner">
<div class="flex-justify-start">
<div class="flex-content">
justfy-content:flex-startだと子要素は左よせになるよ
</div>
</div>
</div>
</div>
.inner {
max-width: 800px;
width: 97%;
margin: 0 auto;
background: skyblue;
}
.flex-justify-start {
display: flex;
justify-content: flex-start;
}
.flex-content {
padding: 10px;
background: #f5f5f5;
}
このコードは、このように表示されます↓
justify-content:flex-end
justify-content:flex-endは、子要素を右によせて配置します。
<div id="content">
<div class="inner">
<div class="flex-justify-end">
<div class="flex-content">
justfy-content:flex-endだと子要素は右よせになるよ
</div>
</div>
</div>
</div>
.inner {
max-width: 800px;
width: 97%;
margin: 0 auto;
background: skyblue;
}
.flex-justify-end {
display: flex;
justify-content: flex-end;
}
.flex-content {
padding: 10px;
background: #f5f5f5;
}
このコードは、このように表示されます↓
justify-content:space-around
justify-content:space-aroundは、子要素全ての左右余白を均等にして配置します。
<div id="content">
<div class="inner">
<div class="flex-justify-space-around">
<div class="flex-content">
全部の左右の余白が<br />均等
</div>
<div class="flex-content">
全部の左右の余白が<br />均等
</div>
<div class="flex-content">
全部の左右の余白が<br />均等
</div>
</div>
</div>
</div>
.inner {
max-width: 800px;
width: 97%;
margin: 0 auto;
background: skyblue;
}
.flex-justify-space-around {
display: flex;
justify-content: space-around;
}
.flex-content {
padding: 10px;
background: #f5f5f5;
}
このコードは、このように表示されます↓
justify-content:space-between
今回のお話の中心になる、justify-content:space-betweenです。
justify-content:space-betweenは、子要素全ての端から始まって端で終わるように、左右余白も均等にして配置します。
<div id="content">
<div class="inner">
<div class="flex-justify-space-between">
<div class="flex-content">
端から端まで、<br />余白は均等
</div>
<div class="flex-content">
端から端まで、<br />余白は均等
</div>
<div class="flex-content">
端から端まで、<br />余白は均等
</div>
</div>
</div>
</div>
.inner {
max-width: 800px;
width: 97%;
margin: 0 auto;
background: skyblue;
}
.flex-justify-space-between {
display: flex;
justify-content: space-between;
}
.flex-content {
padding: 10px;
background: #f5f5f5;
}
このコードは、このように表示されます↓
justify-content:space-betweenは、widthを指定しなくても均等に配置してくれるので、margin-left:autoとかも要らず、かなりの便利さです。
しかし、便利だからといって使いすぎると、大変なことになります・・・!
justify-contentの問題点:折り返し時に両端に配置されちゃう
まずはこちらをご覧ください。
一見綺麗に配置されているように見えますよね。
先程のデモは、このようなコードになっています。
<div id="content">
<div class="inner">
<div class="flex-space-between">
<div class="flex-child">
<div class="title">
タイトル
</div>
</div>
<div class="flex-child">
<div class="title">
タイトル
</div>
</div>
<div class="flex-child">
<div class="title">
タイトル
</div>
</div>
<div class="flex-child">
<div class="title">
タイトル
</div>
</div>
<div class="flex-child">
<div class="title">
タイトル
</div>
</div>
<div class="flex-child">
<div class="title">
タイトル
</div>
</div>
<div class="flex-child">
<div class="title">
タイトル
</div>
</div>
<div class="flex-child">
<div class="title">
タイトル
</div>
</div>
<div class="flex-child">
<div class="title">
タイトル
</div>
</div>
</div>
</div>
</div>
* {
box-sizing: border-box;
}
body {
margin: 0;
}
.inner {
max-width: 1000px;
width: 97%;
margin: 0 auto;
background: red;
}
.title {
font-size: 18px;
text-align: center;
}
@media screen and (max-width: 500px) {
.title {
font-size: 12px;
}
}
/*ここからflexbox*/
.flex-space-between {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.flex-child {
width: 31.5%;
background: #f2f2f2;
border: 1px solid #888;
padding: 10px 0;
margin-top: 15px;
}
flex-wrap:wrapがあるので、3つになった時点で折り返しています。
上のコードでは、親要素.flex-space-betweenにjustify-content:space-betweenを、
子要素.flex-childにwidth:31.5%を指定しているので、左右余白が均等に端から端まで綺麗に配置されています。
「余白をもっと広げたい!」あるいは、「余白をもっと狭めたい!」という場合は、.flex-childのwidth:31.5%を大きくしたり小さくしたりするだけでいいので、すごく便利です。
これを知ったとき僕はすごく感動して、これをあるWordPressサイトの投稿一覧ページを、justify-content:space-betweenを使って作成しようと試みました。
しかし、そこで問題が・・・。
折り返して2つ並びになった時に、変な表示になっちゃった!
↑こんな感じで、折り返した行の時、両端に配置されてしまったんです!
WordPressの投稿一覧ページは、投稿数が必ず決まっているわけではなく、
ユーザーが投稿した数に応じて変わるわけです。
投稿数が、毎回3の倍数であれば綺麗配置されるのですが、折り返して1個または2個残ってしまうと、その行の中で余白を均等に保とうとして、このようにおかしな配置になるのです。
本来ならば、こうあってほしいですよね。
↑のようにするにはどうすれば良いのか。
せっかく覚えたjustify-content:space-betweenを早く使いたい私、五平餅くんはなんとかうまく実現できないか試行錯誤しました。
しかし、結論は・・・。
折り返し時に両端に配置されちゃう問題の対処法
諦めました^^
justify-content:space-betweenを諦めることにしました。
では、どうするのか。
ここは、正攻法でいきます。flex+paddingで解決できます。
<div id="content">
<div class="inner">
<div class="flex-margin">
<div class="flex-margin-child">
<div class="flex-content">
<div class="title">
タイトル
</div>
</div>
</div>
<div class="flex-margin-child">
<div class="flex-content">
<div class="title">
タイトル
</div>
</div>
</div>
<div class="flex-margin-child">
<div class="flex-content">
<div class="title">
タイトル
</div>
</div>
</div>
<div class="flex-margin-child">
<div class="flex-content">
<div class="title">
タイトル
</div>
</div>
</div>
<div class="flex-margin-child">
<div class="flex-content">
<div class="title">
タイトル
</div>
</div>
</div>
<div class="flex-margin-child">
<div class="flex-content">
<div class="title">
タイトル
</div>
</div>
</div>
<div class="flex-margin-child">
<div class="flex-content">
<div class="title">
タイトル
</div>
</div>
</div>
<div class="flex-margin-child">
<div class="flex-content">
<div class="title">
タイトル
</div>
</div>
</div>
</div>
</div>
</div>
* {
box-sizing: border-box;
}
body {
margin: 0;
}
.inner {
max-width: 1000px;
width: 97%;
margin: 0 auto;
background: red;
}
.title {
font-size: 18px;
text-align: center;
}
@media screen and (max-width: 500px) {
.title {
font-size: 12px;
}
}
/*************************************:
justfy-contentを諦めてHTMLを複雑にしてやる方法
***************************************/
.flex-margin {
display: flex;
flex-wrap: wrap;
margin-left: -15px;
margin-right: -15px;
}
.flex-margin-child {
width: calc(100% / 3);
padding: 15px 15px 0;
}
.flex-content {
background: #f2f2f2;
border: 1px solid #888;
padding: 10px 0;
}
解説すると、このようになります。
- 親要素.flex-marginには、justify-content:space-betweenを指定しません。
- 子要素を、.flex-margin-childの中に.flex-contentという2段構成にします。
- .flex-margin-childは親要素が見えなくなるように幅いっぱいにwidthを指定し、左右のpaddingで余白を作ります。
- 一つ目の左paddingと3つ目の右padding分が空いてしまうので、親要素を同じ数値をマイナスにして左右にmarginを指定します。
- .flex-contentにお好きなようにcssでデザインを作ります。
.flex-margin-childのwidthにcalc(100% / 3)という値が出てきましたが、この「calc(〇〇)」は計算ができる便利な値です。
この場合は、100%を3で割っていますので、一行で3つの要素をいっぱいに広げているということです。
この作り方は、justify-content:space-betweenに比べればHTMLが複雑になりめんどくさいと思われるかもしれませんが、例えば「一行をやっぱり4つにしたい」とか「5つにしたい」と思った時にすぐに変えられる便利な書き方です。
例)一行を4つにしたい場合
<div id="content">
<div class="inner">
<div class="flex-margin4">
<div class="flex-margin-child4">
<div class="flex-content4">
<div class="title">
タイトル
</div>
</div>
</div>
<div class="flex-margin-child4">
<div class="flex-content4">
<div class="title">
タイトル
</div>
</div>
</div>
<div class="flex-margin-child4">
<div class="flex-content4">
<div class="title">
タイトル
</div>
</div>
</div>
<div class="flex-margin-child4">
<div class="flex-content4">
<div class="title">
タイトル
</div>
</div>
</div>
<div class="flex-margin-child4">
<div class="flex-content4">
<div class="title">
タイトル
</div>
</div>
</div>
<div class="flex-margin-child4">
<div class="flex-content4">
<div class="title">
タイトル
</div>
</div>
</div>
<div class="flex-margin-child4">
<div class="flex-content4">
<div class="title">
タイトル
</div>
</div>
</div>
<div class="flex-margin-child4">
<div class="flex-content4">
<div class="title">
タイトル
</div>
</div>
</div>
<div class="flex-margin-child4">
<div class="flex-content4">
<div class="title">
タイトル
</div>
</div>
</div>
<div class="flex-margin-child4">
<div class="flex-content4">
<div class="title">
タイトル
</div>
</div>
</div>
<div class="flex-margin-child4">
<div class="flex-content4">
<div class="title">
タイトル
</div>
</div>
</div>
</div>
</div>
</div>
* {
box-sizing: border-box;
}
body {
margin: 0;
}
.inner {
max-width: 1000px;
width: 97%;
margin: 0 auto;
background: red;
}
.title {
font-size: 18px;
text-align: center;
}
@media screen and (max-width: 500px) {
.title {
font-size: 12px;
}
}
/*************************************:
4つ並び
***************************************/
.flex-margin4 {
display: flex;
flex-wrap: wrap;
margin-left: -10px;
margin-right: -10px;
}
.flex-margin-child4 {
width: calc(100% / 4);
padding: 15px 10px 0;
}
.flex-content4 {
background: #f2f2f2;
border: 1px solid #888;
padding: 10px 0;
overflow: hidden;
}
変わったのは、親要素の左右マイナスmarginの値と子要素のpaddingの値、width: calc(100% / 3)がwidth: calc(100% / 4)になったことだけです。
次は少し応用です。
おまけ:折り返し時に両端に配置されちゃう問題の対処法〜SCSSで@mixin化〜
SCSSを使っていない人は飛ばしてOKです。
SCSSを使っている方なら、mixinで関数のようにしても便利かもしれません。
※SCSSの説明は割愛します。
※.innerや.title等は先程のcssと全く同じです。
/************************************:
mixin
**************************************/
@mixin flex-margin($number,$side-padding,$top-padding) {
display: flex;
flex-wrap: wrap;
margin-left: $side-padding*(-1);
margin-right: $side-padding*(-1);
.flex-margin-child#{$number} {
width: calc(100% / #{$number});
padding: $top-padding $side-padding 0;
}
}
.flex-margin3 {
@include flex-margin(3,15px,15px);
}
.flex-margin4 {
@include flex-margin(4,10px,10px);
}
出力されるcssは、こちらです。
/************************************:
mixin
**************************************/
.flex-margin3 {
display: flex;
flex-wrap: wrap;
margin-left: -15px;
margin-right: -15px;
}
.flex-margin3 .flex-margin-child3 {
width: calc(100% / 3);
padding: 15px 15px 0;
}
.flex-margin4 {
display: flex;
flex-wrap: wrap;
margin-left: -10px;
margin-right: -10px;
}
.flex-margin4 .flex-margin-child4 {
width: calc(100% / 4);
padding: 10px 10px 0;
}
@includeで呼び出すときに、
$numberに一行に並べたい数、
$side-paddingに横並び要素の左右余白、
$top-paddingに横並び要素の上マージン
を引数に指定するのみでいい感じに並べてくれるので、便利ではないでしょうか。
横スクロール対策
※2022年9月5日追記
今回ご紹介させていただいたflex+paddingはこれだけでも全然使えるのですが、
画面が小さくなった際に、スマホなどで横スクロールが発生したり、画面左右の余白がやたら大きくなる可能性があります。
その際は、下記のようにHTMLとCSSを編集してください!
<!-- id="content"の箇所に、class="flex-margin-wrap"を追加 -->
<div class="flex-margin-wrap" id="content">
<div class="inner">
<div class="flex-margin">
<div class="flex-margin-child">
・・・・
</div>
<div class="flex-margin-child">
・・・・
</div>
<div class="flex-margin-child">
・・・・
</div>
<div class="flex-margin-child">
・・・・
</div>
・・・・・・・・
</div>
</div>
</div>
</div>
.flex-margin-wrap {
overflow: hidden;
}
上記のコードは、画面が小さくなったら縦並びにして親要素.flex-marginのmargin、子要素.flex-margin-childのpaddingを0に戻す場合は必要ない可能性があります。
画面が小さくなったときに横スクロールが発生したり、画面左右の余白がやたら大きくなる現象が発生したら、このように対応していただければと思います!
まとめ:どういう時にjustify-content:space-betweenを使い、どういう時に使わない方が良いのか?
というわけで、まとめです。
横並びにしたい子要素の数が不確定の場合はjustify-content:space-betweenを使わない
justify-content:space-betweenはすごく便利です。
しかし、横並びにしたい子要素の数が不確定の場合は使わない方が良いでしょう。
例えば、「横並び要素が絶対6つ!」みたいに数が決まっていて今後も変化しない場合は、justify-content:space-betweenをどんどん使っていきましょう。
しかし、WordPressの投稿一覧ページのように数が前後して未確定の場合は、flex+paddingが無難です。
横並び要素の数が不確定の場合は、WordPressのオリジナルテーマを作る上で出会う機会が多いと思いますので、ぜひこちらを知識として覚えておいてください!
最後までご覧いただき、ありがとうございました!