画像とキャプションを横に並べて列挙する

染井吉野
「桜の花が咲くと人々は酒をぶらさげたり団子をたべて花の下を歩いて絶景だの春ランマンだのと浮かれて陽気になりますが、これは嘘です。」(坂口安吾 『桜の森の満開の下』)

横並びのキャプション付き画像リストをどのように実装しよう? 左に画像を配置して、右にはそのキャプションを表示するというものを考えています。画像サイズは一律にしよう。キャプションと常に一対一で使用する。でもそのセット数は決まっていません。

リストは、dl 要素とその子要素によってマークアップしてあります。

<dl class="caption-list">
  <dt>[画像]</dt>
  <dd>キャプション<dd>
  <dt>[画像]</dt>
  <dd>キャプション<dd>
</dl>

画像サイズは 160px x 120px でボーダー幅 1px という想定です。

1. フロートによる実装

float プロパティを使う方法。dt 要素と dd 要素とのどちらが高くなるかが分からないため、両要素に float : left を指定して、dt 要素には clear : left も指定する。このままではリストを終えても dd 要素の float が働いてしまうため、dl 要素に後続する要素にも clear を指定する。clearfix は気持ちが悪い。後続要素に何が来るかは分からない。だから、隣接セレクタと全称セレクタを組み合わせて後続要素に適用させます。clear プロパティの適用対象はブロック要素に限られるため、display : block もそこに指定します。

dl.caption-list dt {
  clear : left;
  float : left;
  width : 162px;
}
dl.caption-list dd {
  float : left;
  width : 338px;
}
dl.caption-list + * {
  clear : left;
  display : block;
}

補足

運用上は、ブロック要素以外が後続要素に来ることは加筆修正時の ins ・ del 要素のみに限られそう。ということは、display : block はその二つに適用させるよう書くだけで事足りるはずです。

2. ネガティブマージンによる実装

margin プロパティを使う方法。dd 要素の左マージンに dt 要素の幅を指定して、画像とキャプションとが重ならないようにする。後は dt 要素の下マージンか dd 要素の上マージンかのどちらかに dt 要素の高さを負の数として指定すれば横に並んでくれる。ただし、dt 要素の高さが dd 要素よりも高いときには後続要素が重なるという不具合が起きてしまう。そのため、dt 要素の高さと同じかそれ以上に常になるように dd 要素の高さを指定します。

/* 下マージンに負の数の場合 */
dl.caption-list dt {
  margin-bottom : -122px;
}
dl.caption-list dd {
  height : 122px;
  margin-left : 162px;
}

/* 上マージンに負の数の場合 */
dl.caption-list dd {
  height : 122px;
  margin-left : 162px;
  margin-top : -122px;
}

補足

dd 要素の高さを固定したことで、その高さを超える量のキャプションを書くことができなくなってしまいました。overflow プロパティは使いたくない。コーディングで内容が制限されるのはどうにも上手くない。これでは高さを固定する前の状況と本質的には変わりがありません。なぜなら、dt 要素の高さを超える量のキャプションを常に書いていればその状況でも機能するのですから。

3. フロートによる実装 (dd 要素高さ固定)

内容に制限されてもよいのだったら、フロートを使った別の方法も考えられます。今度は dt 要素にのみ float : left を指定します。後は dd 要素の左マージンに dt 要素の幅を指定すれば横に並んでくれる。ただし、dt 要素の高さが dd 要素よりも高いときには後続要素が回り込むという不具合が起きてしまう。そのため、dt 要素の高さと同じかそれ以上に常になるように dd 要素の高さを指定します。clear を指定する必要はありません。dd 要素の高さが保証されたのですから。

dl.caption-list dt {
  float : left;
  width : 162px;
}
dl.caption-list dd {
  height : 122px;
  margin-left : 162px;
}
dl.caption-list img {
  vertical-align : bottom;
}

補足

画像しか含まれていないとしても、dt 要素の高さが画像の高さと同じになるとは限りません。その高さは、垂直方向の位置の指定と画像の高さとによって決定されるからです。垂直方向の位置を決める vertical-align プロパティに bottom が指定されているなら、dt 要素と画像との高さは等しくなります。ですが、baseline が指定されているときには、ディセンダー (p や y や j などの下に延びた部分) の高さと画像の高さとの総和が dt 要素の高さになるため、dt 要素のほうが dd 要素よりも高くなってしまう。画像を縦に並べたときに僅かな隙間ができてしまう現象の理由の一つがこれでしょう。なお、vertical-align プロパティの初期値は、レンダリングモードによって baseline と bottom とが混在しています。このことも併せて覚えておきたいところ。

今日学んだこと

dl 要素による横並びのキャプション付き画像リストの作り方。