display flexで孫要素まで揃える方法【CSS】

この記事の前提条件

対象: CSS(全モダンブラウザ対応)
難易度: ★☆☆
所要時間: 約5分

親要素にdisplay: flex;align-items: center;を指定して子要素を中央揃えにしたのに、子要素の中に入れたアイコン+テキストがなぜか中央に揃わない——アイコン付きボタンやカードのヘッダーなど、要素を入れ子にするレイアウトでよく起きるつまずきです。

なぜ孫要素には効かないのか

justify-contentalign-itemsは、「flexコンテナの直接の子要素」にしか効きません。孫要素(子要素のさらに中の要素)には、影響が及ばないのがflexboxの仕様です。つまり、孫要素を揃えたい場合は、その子要素自体を「新しいflexコンテナ」にしてあげる必要があります。

子要素自身にもdisplay: flexを指定する

例えば、アイコンとテキストを横並びで中央揃えにしたいボタンを考えます。

<div class="button">
  <span class="button-inner">
    <img src="icon.svg" alt="">
    <span>送信する</span>
  </span>
</div>

.button(親)にdisplay: flex;を指定しても、その効果は直接の子である.button-inner止まりです。アイコンとテキスト(孫要素)まで横並び・中央揃えにするには、.button-inner自身にもdisplay: flex;を指定します。

.button {
  display: flex;
  justify-content: center;
  align-items: center;
}

.button-inner {
  display: flex;       /* 自身も新しいflexコンテナにする */
  align-items: center;
  gap: 8px;
}

こうすることで、.button-innerの中にあるアイコンとテキスト(孫要素)も、それぞれ独立したflexboxのルールで中央揃え・間隔調整ができるようになります。

💡 何階層あっても考え方は同じ

ひ孫要素、さらにその先まで揃えたい場合も同じ考え方で、揃えたい要素の「直接の親」にdisplay: flex;を指定していけば対応できます。ネストが深くなるほど見通しが悪くなりやすいので、揃える階層をむやみに増やさず、可能ならHTML構造自体をシンプルにできないか検討するのもおすすめです。

まとめ

  • justify-contentalign-itemsは「直接の子要素」にしか効かない
  • 孫要素まで揃えたい場合は、間にある子要素自身にもdisplay: flex;を指定する
  • 階層が深い場合も、揃えたい要素の直接の親に指定していけば同じ考え方で対応できる

アイコン付きボタンやカードのヘッダー部分など、要素を入れ子にするレイアウトで特によく使う考え方です。