CSSのvertical-alignについて

大前提として、僕の知識は基本的にCSS2止まりです。また、Webデザイナーでもありません。今は(css3では)こうするのがトレンドだよーとかあれば教えて頂けると大変喜びます。

昨夜twitter403 Forbiddenという記事を紹介してもらった。確かに昔ハマったことあるなーと思いつつvertical-alignで検索しようとしたら「vertical-align 効かない」が候補に出てきた。結構みんなはまってるんですね。

vertical-alignはblock要素には適用できない

まず最初にハマるポイント。こいつはinline, inline-block, table-cellに対してしか効かない。block要素には適用することができない。
昔懐かしいtableレイアウトの感覚で

div#hoge { vertical-align: middle; }

なんてしても全く意味が無い。「vertical-align 効かない」でググってるのは大抵このパターン。

具体的に見ていく

インライン要素
baseline インラインボックスのbaseline(無ければその下辺を)親ボックスのbaselineに揃える
middle インラインボックスの中心を親ボックスのbaselineから0.5ex上げる。(0.5exは小文字の"x"の半分の高さ)
sub インラインボックスのbaselineを親ボックスの下付き文字として適切な位置まで下げる。
super インラインボックスのbaselineを親ボックスの上付き文字として適切な位置まで上げる。
text-top インラインボックスの上辺を親要素のfontの下辺に揃える
text-bottom インラインボックスの下辺を親要素のfontの上辺に揃える
top インラインボックスの上辺を行ボックスの上辺に揃える
bottom インラインボックスの下辺を行ボックスの下辺に揃える

具体的にはこう。
f:id:kk6:20111218162111j:image

また、これには長さやパーセンテージを指定することも出来る。

長さ 指定した長さの分だけボックスを上げ下げする。(マイナス値で下がる)0を指定すればbaselineを指定したのと同様の効果。
パーセンテージ line-heightに対して指定した%だけblockを上げ下げする。(マイナス値で下がる)0%を指定すればbaselineを指定したのと同様の効果。

具体的にはこうなる。

f:id:kk6:20111218162120j:image

親ブロックの上辺が押し上げられちゃってますね。

ちなみにあたり前のことだけど、基準となる親要素が存在しなければvertical-alignを指定しても効果は得られない。

セル要素

f:id:kk6:20111218162056j:image

なんか昔と挙動が違うんですけど。
上から順に

  • 1行目:最初のセルには何も指定していない
  • 2行目:最初のセルにvertical-align: baseline;を指定
  • 3行目:最初のセルにvertical-align: bottom;を指定

昔は1行目の2番目のセルは最初のセルのフォントのベースラインに揃えられてたと思うんだけどなぁ。2行目は最初のセル自体にvertical-align:baseline;を指定してみた。すると行のbaseline自体が書き換えられた模様。最初のセルにbaselineを指定していない場合のベースラインはCSSを一切適用していない時点(規定のフォントサイズの時)のベースラインなのかなー、といった結論に至った。

というわけでまとめるとこんな感じかな。

baseline 指定したセルをそれを含む行の最初のセルのベースラインに揃える。
middle 指定したセルをそれを含む行の中心線と揃える
top 指定したセルをそれを含む行の上辺に揃える
bottom 指定したセルをそれを含む行の下辺に揃える

[sub, super, text-top, text-bottom]はセル要素には適用できない、と説明してるサイトが多いけど、それだけだとちょっと説明不足で、正しくは「適用されない代わりに既定値であるbaselineを適用する」。vertical-alignをそもそも指定しないのと、セルに対して適用できないsubなどを指定するのとでは挙動が違うのです。

じゃあブロック要素の垂直位置を真ん中に指定した場合はどうするの

position要素でblockを相対配置する

display: table-cell;とする、なんて記事も見かけたけど、表に全然関係ない要素にこれを指定するのはなんだか気持ち悪い。

line-heightの値を親blockのheightの値と揃える、なんていうのもなんとなくバッドノウハウな気が。内包するinline要素でvertical-alignを長さで指定した場合、inline要素のline-heightが変わっちゃうだろうからおかしなことになるんじゃないかな。試してないけど。

block要素の配置には基本的にposition, top, right, bottom, leftそれぞれを指定するというのが昔僕が学んだ方法なんだけど、今のトレンドはどうなんだろう。
ちなみに、これにもちょっとした罠がある。相対配置にする場合はposition: relative;を指定してやるんだけど、親blockとの相対位置ではなくて、自身の本来の位置からの相対位置なので 例えば内側のdiv要素(仮にid="inner"を指定していたとする)にtop: 50%; としても、#innerの上辺が真ん中に来てしまい、ブロックそのものは真ん中よりちょっと下に見えるだろう。なのでまあ表示をみながらちょうどいい数値を探るしかないですよね。

でもきっと今はもっとスマートな方法があるに違いない!
...あるといいな。