💪

flexで子要素の増減に耐える

2021/12/23に公開

justify-content: space-between;を使わない

図解: 10個の四角形を4列3行のグリッド状に配置している。横方向の余白は32px、縦方向の余白は24px。

上図のような4列レイアウトを作る時、僕はjustify-content: space-between;をあまり使わないです。要素が増えたり減ったりして、最後の行が2列または3列になったらレイアウトが崩れてしまうからです。

この問題を解決するために、僕は親要素にネガティブマージンを使っています。ネガティブマージンとは、マイナスの値を指定したmarginのことです。マイナスの値を指定すると、その方向に要素が引っ張られます。この性質を利用することによって、flexの4列レイアウトは子要素の増減に耐えることができます。

4列レイアウトを作ってみる

子要素同士の左右の余白が32px、上下の余白が24pxの4カラムレイアウトを作ってみます。

手順

  1. 親要素にはflex-wrap: wrap;を指定する
  2. ネガティブマージンで親要素を上に引っ張る
  3. ネガティブマージンで親要素を左に引っ張る
  4. プラスのマージンを上と左に持たせた子要素を並べる

※HTMLは下記とします。

<ul class="flex-parent">
  <li class="flex-child"></li>
  <li class="flex-child"></li>
  <li class="flex-child"></li>
  <li class="flex-child"></li>
  <li class="flex-child"></li>
  <li class="flex-child"></li>
  <li class="flex-child"></li>
  <li class="flex-child"></li>
  <li class="flex-child"></li>
  <li class="flex-child"></li>
</div>

1.親要素にはflex-wrap: wrap;を指定する

.flex-parent {
  display: flex;
  flex-wrap: wrap;
}

2.ネガティブマージンで親要素を上に引っ張る

図解: margin-top: -24px;を指定することで指定する前に比べて、24px分、上方向に配置されている図。

子要素同士の上下余白と同じだけのネガティブマージンを親要素に指定します。今回は上下の余白が24pxなので、親要素にmargin-top: -24px;を指定します。
すると、親要素は上方向に24px引っ張られます。

.flex-parent {
  display: flex;
  flex-wrap: wrap;
  margin-top: -24px;
}

3.ネガティブマージンで親要素を左に引っ張る

子要素同士の左右余白と同じだけのネガティブマージンを指定します。今回は上下の余白が32pxなので、親要素にmargin-top: -32px;を指定します。
すると、親要素は左方向に32px引っ張られます。

.flex-parent {
  display: flex;
  flex-wrap: wrap;
  margin-top: -24px;
  margin-left: -32px;
}

4.プラスのマージンを上と左に持たせた子要素を並べる

子要素には、上に24px、左に32pxのマージンを指定します。
さらに、子要素には横幅も指定します。
まず、4列なので4等分にするために4で割ります。
100% / 4 = 25%
そして、左マージン分を引いた値を指定します。

.flex-child {
  margin-top: 24px;
  margin-left: 32px;
  width: calc(25% - 32px);
}

並べていくと下図のように、並べることができます。

手順は以上です。
出来上がった4列レイアウトの子要素の数を増減させても崩れないと思います。

応用すればこういうレイアウトにも使える

ここまで4列レイアウトを例にしてきましたが、例えばタグを並べるようなレイアウトにも使えます。

この場合は、子要素の横幅は指定しないようにします。文字数に応じた横幅にするためです。並べられたタグはその行に入りきらなければ次の行に折り返されます。

おわりに

上と左にネガティブマージンを指定する以外にも、親要素の上下左右にネガティブマージンを指定する方法や子要素にはborderやpaddingを使う方法も見たことがあります。
考え方は似ているので、この記事の内容を知っていると応用が効くかもしれません。

Discussion