画像を縦に2枚、3枚と並べただけなのに、なぜか画像と画像の間に数ピクセルのすき間ができる。バナーを隙間なくぴったり積み重ねたいのに、薄い線のような余白が消えてくれない。CSSをいくら見直しても margin も padding も指定していないのに、どうしても詰まらない。私もWeb制作を始めたての頃、この現象にずいぶん時間を取られました。
当時は「Firefoxで見たときだけすき間が出る」と思い込んでいたのですが、これは特定のブラウザのバグではありません。HTMLとCSSの仕様どおりに起きる、ごく当たり前の挙動です。だから一度仕組みを理解すれば、どのブラウザでも同じ理屈で説明がつきますし、原因さえ分かれば対処はたった一行で済みます。逆に仕組みを知らないまま margin や padding をいじり続けると、いつまでも消えずに消耗してしまうやっかいな相手でもあります。
この記事では、縦に並べた画像のすき間が生まれる本当の原因(imgがインライン要素であること)と、display:block・vertical-align・font-size:0・line-height:0・Flexbox/Gridという5つの対処法を、それぞれの効きと使い分けまでコード付きで解説します。
原因を一度きちんと理解しておくと、画像だけでなくボタンやアイコン、インライン要素全般の「謎の余白」にも応用が利きます。長年Web制作をしてきて、いまだに新人さんから一番よく相談されるテーマでもあるので、つまずきやすいポイントを順に押さえていきましょう。
なぜ縦に並べた画像のすき間ができるのか
先に結論を言うと、原因は img 要素が初期状態で「インライン要素」として扱われることにあります。文章の中の文字と同じ仲間として配置されるため、画像も文字のルールに従って並べられます。
文字を並べる行(行ボックス)には「ベースライン」という基準線があります。アルファベットの「a」や「e」が乗っている、あの下の線です。一方で「g」「y」「p」のように、ベースラインより下にはみ出す部分を持つ文字もあります。この下にはみ出す部分を「ディセンダ(descender)」と呼びます。
ブラウザは、インライン要素である画像を初期値 vertical-align: baseline でこのベースラインに揃えます。そして「この行にはディセンダを持つ文字が来るかもしれない」と想定して、ベースラインの下にあらかじめ余白を確保します。実際にはそこに文字がなくても、画像の下に「ディセンダ分のすき間」が空いてしまう。これがあのすき間の正体です。
MDNでも、vertical-align の初期値 baseline は要素のベースラインを親のベースラインに揃えると明記されています。すき間は画像の margin ではなく、行ボックスの構造そのものから生まれているので、いくらマージンを0にしても消えないわけです。
<div class="box">
<img src="banner1.png" alt="バナー1">
<img src="banner2.png" alt="バナー2">
</div>
上のように画像を素直に並べると、画像と画像のあいだ、そして画像と親要素の下端のあいだに、フォントサイズや行の高さに応じた数ピクセルのすき間が現れます。HTMLのソース内で img タグの前後に改行や空白を入れていると、その空白文字が行ボックスを生み、すき間がより目立つこともあります。
かつて「Firefoxだけで出る」と言われがちだったのは、ブラウザごとにデフォルトの行の高さや余白の扱いに微妙な差があり、その差で見え方が変わったためです。原因は仕様どおりの挙動なので、現在のChrome・Edge・Safari・Firefoxのいずれでも基本的に同じことが起こります。
参考: MDN Web Docs: vertical-align
対処法1:display:blockで一番ラクに消す
一番おすすめで、迷ったらこれで良いのが display: block です。画像をインライン要素からブロック要素に変えてしまえば、行ボックスやベースラインの世界から抜け出すので、ディセンダ分のすき間そのものが発生しなくなります。
img {
display: block;
}
MDNでも、要素を display: block にすると前後で改行が入り、インラインの整形コンテキストから外れると説明されています。つまり「文字のルール」で配置されなくなるので、ベースラインに揃える処理自体が起きません。一行書くだけで原因を根本から断てる、もっとも確実な方法です。
注意点は、ブロック要素になると画像が前後で改行され、横並びにはできなくなることです。バナーを縦に積む・写真を1枚ずつ積み上げるといった「縦並び」の用途には最適ですが、画像を横にいくつも並べたい場面では次以降の方法が向きます。
関連記事:CSSのfloatとは?回り込み・clearfix・Flexboxの使い分けを解説
対処法2:vertical-alignで揃え位置をずらす
画像をインラインのまま使いたい(横並びを残したい、テキストと混在させたい)ときに効くのが vertical-align です。すき間の原因はベースライン揃えなので、揃える位置をベースラインから変えてしまえば、ディセンダ用の余白が効かなくなります。
img {
vertical-align: bottom;
}
vertical-align: bottom は画像の下端を行ボックスの下端に揃えるため、ベースラインの下に確保されていた余白の影響を受けなくなり、すき間が消えます。同じく top や middle でもすき間は解消しますが、揃える位置が変わるので見た目が変化します。縦に画像を積む用途なら bottom が直感的で扱いやすいです。
ここで知っておきたいのが、MDNが整理している bottom と text-bottom の違いです。bottom は「行全体の下端」に揃えるのに対し、text-bottom は「親のフォントの下端」に揃えます。文字とアイコンを並べて高さを揃えたいときは text-bottom が便利な場面もあるので、用途で選び分けてください。
なお vertical-align が効くのはインライン要素・インラインブロック要素・テーブルセルだけです。すでに display: block にした要素には効きません。あくまで「インラインのまま直したい」ときの選択肢です。
参考: MDN Web Docs: vertical-align
対処法3:親要素のfont-size:0・line-height:0で抑える
画像の側ではなく、画像を包む親要素の側から余白を潰す方法もあります。すき間は「行ボックスの高さ」に由来するので、行の高さを生み出している font-size や line-height を0にしてしまえば、すき間の元になる空間そのものをなくせます。
.box {
font-size: 0;
line-height: 0;
}
line-height: 0 は行の高さを0にしてベースライン下の余白を消します。font-size: 0 は、HTMLソース内の改行や半角スペースが生む「タグ間の空白」も同時に潰せるのが利点で、画像を横並びにしたときに出るすき間にも効きます。
ただしこの方法には大きな副作用があります。親要素に font-size: 0 を指定すると、その中のテキストも0pxになって表示されなくなります。古い記事では「.Rbox に line-height:0 を入れる」と書いていましたが、ボックス内に説明文やキャプションがあると行間が詰まったり文字が消えたりするので注意が必要です。
対策として、画像だけを別の要素で囲み、テキストには改めて font-size を指定し直すのが安全です。テキストを含まない、画像だけのまとまりに限定して使うのが現実的な使いどころと言えます。
対処法4:Flexbox / Gridで並べて根本回避する
現在のレイアウトなら、私はこの方法を一番すすめています。親要素を display: flex や display: grid にすると、その中の画像はインラインの整形コンテキストから外れるため、ベースライン由来のすき間が最初から発生しません。
.box {
display: flex;
flex-direction: column;
}
縦に積むなら flex-direction: column、横に並べるなら初期値の横並びのまま使えます。MDNでも、要素を flex や grid にするとインラインの整形コンテキストから外れると説明されており、ベースライン揃えの処理が走らなくなるのが効く理由です。
関連記事:CSS calc()の使い方と実務例!よくあるレイアウトパターンも紹介
この方法の強みは、すき間を消すだけでなく、画像同士の間隔を gap プロパティで自由にコントロールできる点です。「すき間を0にしたい」だけでなく「狙った間隔で等間隔に並べたい」という要件まで一括で満たせるので、複数の画像をギャラリー状に並べる場面では特に相性が良いです。
.box {
display: grid;
gap: 8px;
}
1枚2枚の単純な縦積みなら display: block で十分ですが、複数枚をきれいに整列させたい・レスポンシブで折り返したいといった要件があるなら、最初からFlexboxやGridで組むほうが後々ラクです。
まとめ:原因はベースライン、対処は用途で選ぶ
縦に並べた画像のすき間は、ブラウザのバグでも自分のミスでもありません。img がインライン要素で、文字のベースラインに揃えられ、ディセンダ分の余白が確保されることで生まれる、仕様どおりの現象です。この一点さえ腑に落ちれば、対処法はどれを選んでも筋が通って見えてきます。
使い分けの目安はシンプルです。とにかく早く確実に消したいなら display: block。横並びやテキストとの混在を残したいなら vertical-align: bottom。テキストを含まない画像のまとまりなら親に font-size: 0 と line-height: 0。そして複数枚を間隔まで含めてきれいに並べたいなら、最初からFlexboxやGridで組む、という順で考えると迷いません。
一つだけ気をつけたいのは、font-size: 0 はテキストまで消してしまう副作用があること。画像とキャプションが同じ箱に同居しているときは、画像だけ別要素で囲うか、別の方法に切り替えてください。
私自身は、新規に組むレイアウトなら display: block かFlexbox/Gridで最初から余白を作らない方針にしています。後から「すき間が出た」と慌てて打ち消すより、構造の段階で発生させないほうが結局速いし崩れにくいからです。インライン要素の余白という仕組みを一度押さえておけば、画像に限らずボタンやアイコンの「謎の余白」にも同じ理屈で立ち向かえます。次に余白に悩んだら、まず「これはインライン要素か?」と疑ってみてください。