🚥

CSS で横並びの画像とテキストを、テキストが単行の時は縦中央寄せ、複数行の時は縦上寄せ、を実現する

2023/08/13に公開

タイトルの通りですが、アイコンなどの画像と文字数が決まっていないテキストを横並びで表示したい時、文字数や画面幅によってテキストの行数が変わってしまいます。

その時に、単行(厳密には画像の高さよりも低い)の場合は画像の縦中央寄せ、複数行(厳密には画像の高さよりも高い)の場合は縦上寄せにしたい時があると思います。よくあるパターンとしては、同じ UI で Heading の下に description 的なテキストがある場合とない場合がある時の縦位置調整とかかな。

デザイナーからもよく要望がありますし、そのデザインにもよりますが、個人的にも複数行の時に画像が縦中央になっているのは見た目的にイマイチに見えます。

基本的に、画像とテキストを横並びにする時には Flexbox を使うことが最近では多いです。複雑なものだったら CSS Grid を使う時もありますが、これくらいだったら Flexbox がお手軽楽チンですね。

こんな感じの HTML と CSS を書くと思います。

<div class="icon-text">
  <img src="..." alt="" />
  <h2>Johnny Okafuji</h2>
</div>
.icon-text {
  display: flex;
  align-items: center;
  gap: 8px;
}

このコードを適用するとこんな結果になります。

う〜ん、align-items: center; を入れているので、テキストが単行の場合はいい感じに縦中央になるのですが、さっき書いた通り複数行になるとやっぱりイマイチですね。

どうすれば複数行の時に、いい感じに画像の縦上寄せにできるのでしょうか?

実現方法

まず、上の例の HTML のテキスト部分の h2div で囲ってあげる必要があります。

<div class="icon-text">
  <img src="..." alt="" />
  <div class="text-wrap">
    <h2>Johnny Okafuji</h2>
  </div>
</div>

そして、囲った div をまた display: flex; にして、align-items: center; で縦中央寄せにします。
最初の例で親要素の .icon-text に入れていた align-items: center; は削除して、align-items の初期値の align-items: stretch; を使うようにします。

.icon-text {
  display: flex;
  gap: 8px;
}

.text-wrap {
  display: flex;
  align-items: center;
}

要は 1st レベルの Flexbox は streach で画像とテキストの高さを揃え、2nd レベルの Flexbox で縦中央寄せにしているんですね。画像よりもテキストの高さが低い時はテキストは画像の高さになり中央寄せになる、テキストの方が高い時はそのまま縦上寄せになる感じですね。

以下のデモで実際にそうなっているか確認できます。

デモ

まとめ

多分、知っている人からすると当たり前にやっていることだと思いますが、案外調べてみてもこれを実現する方法が出てこなかったので書いてみました。自分の備忘録のためにも残しておきます。

2024/12/12 追記

上記のやり方だと、div で囲う必要があったり、Line Height やフォントサイズの値によっては綺麗に揃わなかったりするので、アイコンにハーフ・レディング分の上マージンを入れるのが現状いいやり方だと思います。

.icon-placeholder {
  width: 32px;
  height: 32px;
  flex: none;
  background-color: blue;
  border-radius: 50%;
+ margin-top: calc((1lh - 32px) / 2);
}

追記のデモ

Discussion