12周年記念パーティ開催! 2024/5/10(金) 19:00

inline layoutを使いこなす 第1回 画像の余白 1

vertical-align: topの指定で、画像の余白はなぜ消えるのでしょう? 要素がどのようにレイアウトされていくのかinline layoutの仕様を理解すると、なぜそうなるのかがきちんと説明できるようになります。

発行

著者 高津戸 壮 テクニカルディレクター
inline layoutを使いこなす シリーズの記事一覧

はじめに

本シリーズでは、なんとなく使っているけれど、実はあまりよく知らないという人も多いであろうinline layoutについて解説します。

このシリーズで言うinline layoutとは、簡単に言うと、行やdisplayプロパティがinlineinline-blockである要素、またそれに隣接するテキストなど、block box内に配置されるコンテンツが、どのようにレイアウトされ、ブラウザに表示されるかを示した仕様のことを指します。Web上で参照できるW3Cの仕様としては、以下に概ねまとめられています。

筆者は、コーディング中に生じた疑問を調べていったら、上記仕様群を読み込むに至りました。始まりは疑問だったのです。そこでこの記事は筆者が疑問に感じた事象をベースに話を進めていきたいと思います。

なお、紹介するサンプルは次のリポジトリからダウンロード、またはクローンできます。併せて参照してください。

inline layoutサンプルリポジトリ

vertical-align: topで消える余白

コーディングをしていると、次のように画像を配置することがあります。

画像間に20pxの余白を空けたい。なのでこのようにHTMLとCSSを書いたとします。

<div class="photoBlock"><img src="photo.jpg" alt=""></div>
<div class="photoBlock"><img src="photo.jpg" alt=""></div>
<div class="photoBlock"><img src="photo.jpg" alt=""></div>
.photoBlock {
  margin: 0 0 20px;
}

一見問題なさそうに見えますが、このとき.photoBlockに背景色を付けてみると、次のように表示されます。

画像の下に余白ができています。これだと実際には20px以上空いているように見えてしまいますから、この余白部分を消したいです。そこでimgvertical-align: topを当ててやります。

.photoBlock img {
  vertical-align: top;
}

すると、画像直下の余白は消えます。

ちなみにbottommiddleを指定したときも消えます。めでたし。

……なのですが、なぜこのようになるのでしょうか。経験的に使っていた指定ですが、筆者はきちんと理解していなかったので、調べてみることにしました。

このvertical-alignの挙動を理解するには、行がどのようにレイアウトされるのかを理解しなければなりません。まずfont-sizeline-heightの関係から理解していきましょう。

font-sizeとline-heightの関係

次のようなHTMLとCSSがあるとします。

<p><span>The quick brown fox jumps over the lazy dog....</span></p>
p {
  font-size: 16px;
  line-height: 16px;
  background: #a6dbbe; /* green */
}
span {
  background: #f197f1; /* purple */
}

すると次のような表示となります。

このとき、文字の大きさは16pxで、行の高さも16pxです。行ごとに四角で囲むと、次のようになります。

font-sizeline-height16pxなので、文字の大きさも行の高さも16pxという状態です。

line-heightを広げた場合

では、このときline-heightをもっと広げたらどうなるでしょうか。今度はfont-size16pxのままですが、line-height24pxとしました。

p {
  font-size: 16px;
  line-height: 24px;
  background: #a6dbbe; /* green */
}

このときは、次のような表示になります。

さて、文字の大きさと行の高さについて、詳しく見ていきましょう。

このときピンクの間に見える背景のグリーンの部分が、line-heightを指定することで広げられた「行間」となりますが、この部分のことをleadingと言います。

そして、このleadingは次のように、真ん中で半分に分割されます。このように半分に分割されたleadingをhalf-leadingと呼びます。

1行というのはfont-size分の高さを持った基本領域(inline box)の上下にhalf-leading分のスペースが加わり、成り立っています。このとき、1行の高さはline-heightが示す値、この場合で言うと24pxです。この値から基本領域の高さ16pxを引いた8pxがleadingの高さとなり、half-leadingの高さは4pxとなります。

行の高さというのは、このようにfont-sizeline-heightから計算され、決定されています。

inline boxに関わる名称

レイアウトの仕組みをもっと突っ込んで見ていきましょう。各部の名称とともに見ていきます。概要を図にまとめました。

テキストやdisplayinlineinline-blockである要素が配置される場合、まず始めに、それを配置するための箱が最低でもひとつ用意されると考えます。この箱のことをinline boxと呼びます。

紫で色を付けた領域です。テキストが配置される場合、このinline boxの高さが、1em分の高さです。

例えばfont-size: 16pxと指定したら、このinline boxの高さが16pxとなり、16px1emとして扱われるようになるという具合です。

そして、その上下にhalf-leading分の余白が加わり、1行の高さとなります。この高さがline-heightが示す高さとなります。こうして拡張されたinline boxのことを、extended inline boxと呼びます。line-height24pxなら、extended inline boxの高さが24pxとなります。

このinline boxの上端をtext-before-edge、下端をtext-after-edge。extended inline boxの上端をbefore-edge、下端をafter-edgeと呼びます。

土台となるbaseline

inline layoutを考える上で重要なのが、baselineです。

baselineとは、その名が示す通り、文字の土台となるラインです。文字は通常、このbaselineを基準としてデザインされます。そして、ここから一定の距離のラインで、小文字の高さを揃えます。この高さがx-heightです(この高さは、CSS内で1exとして利用できます)。

ちなみに、このbaselineはアルファベットを基準に考えた場合で、日本語などのbaselineは、これよりもちょっと下がbaseline(ideographical baseline)となります。

CSS3の仕様書を見ると、将来的には、このideographical baselineもvertical-alignなどの基準位置として利用できるようになるようです。

行の高さの決まり方

先の例で見た通り、font-sizeline-heightにより行の高さが決まるわけですが、1行の中に複数のinline boxが存在する場合は、それらがすべて収まるように、行の高さが決定されます。

この例では、bemiの3つの要素が1行の中に収まっています。これらの要素を含む行の高さが、ほかの行に比べて高くなっていることに注目してください。

<p>The <b>quick</b> <em>brown</em> <i>fox</i> jumps over the lazy dog. ...</p>
p {
  font-size: 12px;
  line-height: 18px;
  background: #a6dbbe; /* green */
  width: 310px;
}
b {
  font-size: 20px;
  line-height: 30px;
  background: white;
}
em {
  font-size: 30px;
  line-height: 40px;
  background: orange;
}
i {
  font-size: 40px;
  line-height: 50px;
  background: tomato;
}

このとき、1行目では各extended inline boxの配置がチェックされます。

この行では、<i>fox</i>のextended inline box分の高さを確保すれば、すべてのextended inline boxが収まります。ですので、この要素に合わせた50pxの高さが、この行の高さとなります。

このようにしてブラウザは各行についてその行の高さを決定し、レイアウトを行います。

anonymous inline box

この例においてThejumps ...は、特にb、em、i要素では囲われていませんが、これらもinline boxを形成し、行の高さの計算に組み込まれます。このときのfont-sizeline-heightは親要素を継承するため、pfont-size: 12pxline-height: 18pxが適用されます。このように明示的に要素で囲わずに形成されるinline boxをanonymous inline box(匿名インラインボックス)と呼びます。これを架空の要素の形にして考えると、次のようになります。

<p>
  <anonymous>The </anonymous>
  <b>quick</b>
  <anonymous> </anonymous>
  <em>brown</em>
  <anonymous> </anonymous>
  <i>fox</i>
  <anonymous> jumps over the...

実は<b>quick</b><em>brown</em><i>fox</i>の間にもスペースがあるため、ここでもanonymous inline boxが形成されています。

line box

ここまでで見てきたように、各行について、その行が内包するinline box群の高さが評価され、行の高さが決定されます。その行に収まらなかった内容は、次の行が作られ、その行に収められます。そして、その行でも収まらなかった場合はまた次の行へ……と、コンテンツがすべて配置されるまで行が作られ、積み上げられていきます。この「」を表現する領域のことを、line boxと呼びます。

block box内にinline boxが存在する場合、1つ以上のline boxが用意され、その中にinline boxが配置されるといった具合です。例えば今挙げた例では、次のようにline boxが用意されています。

そして、その中に配置されるinline boxは、行をまたぐことができます。例えば、始めの<i>fox</i>の次に配置されるjumps over the ...のテキストを表現するanonymous inline boxは、次に登場する<b>quick</b>に至るまで、行をまたいでずっと続いています。

block box内に配置されるテキストは、このようにline boxとinline boxの入れ子として計算され、レイアウトされています。

次回も引き続き、inline layoutについて見ていきましょう。