わたしと納豆ごはん

納豆、Web、雑記など

vertical-align 考察(よく分からない vertical-align と、和文で中央揃いがズレる問題)

CSS の中でよく分からなかったのがvertical-align です。

vertical-align て特殊ですよね? なんか思うように揃わなかったり、機能しなかったりします。

なんでやねん、よし一度いろいろ実験したろと思っており、やってみました。

まあ知っている方、詳しく方には目新しい情報は皆無です。その場合はダッシュで戻るボタンを押して下さいね(笑)

、大幅加筆・修正)

スポンサーリンク

いろいろやった結果をまとめてみます。しかし、まとめるのって難しい…。

まずはこちらから。

vertical-align は table-cell かインラインの要素でしか使えず、しかもこの二つでは指定方法などが少し違う

これは基礎的なことなので、リファレンスなどで詳しく書かれていますが

vertical-align は table-cellインラインの要素にしか使えません。

インラインの場合、テキストの縦方向を揃えるプロパティなので何となく親要素のブロックレベルに指定すると感覚的に思ってしまうのですが、間違いです(わたしだけか?)。

そしてこの両者、同じ vertical-align でも使える値に違いがあります。これもリファレンスなどで詳しく書かれていますね。

まあ、ややこしいと言うほどでも無いのですが、わたしは頭が悪いからよく分からなくなります。

よく理解するためにも、この2つの違いを少しまとめます。

table-cell の vertical-align

table-cell 要素の場合、vertical-align は親要素である table-cell 要素に設定します

これにより子要素のテキストの縦の位置を「top ・middle・bottom」で上端( top )中央( middle )下端( bottom )に揃えることができるのですが

table-cell 要素ではこの3つ値以外は全て baseline(初期値)となります。パーセント値や em、px といった数値も無効で、初期値の baseline になります。

とはいえインラインと違う所は

  • 親要素(table-cell)に設定する
  • top ・middle・bottom の値だけ使える

この2つだけなので、ややこしいという訳ではありません。

ま、display:table-cellvertical-align:middleを使って、ボックスの中身を中央表示する方法は有名ですので、ご存知の方も多いと思います。

ちなみに vertical-align 初期値のvertical-align:baselineは少々特殊で、複数のtable-cell要素が並んだ横一行で、その全体のテキストの中で、最も低い baseline で揃えるそうです。*1

一行の
 table-cell で baseline で揃っている画像

このことに関しては、こちらの記事が非常に分かりやすくて参考になります。わたしも参考になりました。

terkel.jp

インラインでの vertical-align

インラインの場合、先ほどの紹介したリファレンスにあるように「 top ・middle・bottom 」以外に「text-top・text-bottom・super・sub 」と「パーセント(%)」。それとempxといった「数値+単位」と初期値でもある baseline が指定できます。

ちなみにパーセント(%)を指定した場合、vertical-align を設定したインライン要素の line-height の大きさの割合分移動します。例えば、vertical-align を設定した span の line-height が0の場合、いくらパーセントを指定しても動きません。

ここらへんのことは先ほどのリファレンスと、以下の記事が非常に参考になります。

インラインの vertical-align で揃えているもの

table-cell要素に設定した場合は非常に分かりやすい動きをしてくれるのですが、ややこしいのはインラインの方です。

次はインラインでは何を揃えているのかということに焦点を合わせてみます。

基本的にはフォントや line-height の大きさを基準として揃える

こちらで揃える基準となる基本的には文字と行間です。つまりフォント自体や文字サイズ(font-size)と行間(line-height)の高さが揃える位置に影響を与えています。

※font-size と line-height については、こちらの記事が参考になります。

参考リンク:理解しておきたい、CSSによるインラインレイアウトの仕組み(font-size/line-height編)Inline Layout─Frontrend Conference | HTML5Experts.jp

vertical-align の top と bottom それとパーセント(%)は line-height が関係しています。

これらとは別に text-top、text-bottom、super、sub はフォントに関係していますので、フォントに依存しています。

あと middle と数値+単位ですが、middleは要素の中央、数値+単位は数値分 baseline から動くものです。

この内、テキスト無し(font-size:0)にしたらどうなるかと言えば、工夫次第では line-height だけでも要素を下揃にしたりなどできます。

次のサンプルは table-cell や inline-block を使わずに四角いボックスが下端に揃っているように見せたものです。

黄色の四角いものはインラインの span 要素なのですが padding を使ってそれっぽく見せています。

このとき text-top と super は「top」、text-bottom と sub は「bottom」と同じ位置に表示されます。

逆に揃える要素が両方共line-height:0ならば top、bottomは機能しません。または機能しても位置が変わりません。

ただし、text-top・text-bottom・super・sub は機能します。

まあ、font-size や line-heigh を0にすることはあまりありませんけども、vertical-align の動きかたを何となくつかめた感じがします。

要素が display:inline-block で高さ(height)が設定されている時は、そちらが優先される。

インラインにはもう一つの表示形式 inline-block があるのですが、これが入ってくると、ちょっとややこしくなるのです。

この inline-block の要素に vertical-align を指定すると、inline-block の高さを揃える要素にするのですが。

ここで height プロパティが指定してあると、こちらの方で位置が揃います。

百聞は一見にしかずです。次のサンプルを見てください。

サンプルでは span にvertical-align:bottomが設定されています。なのにテキストではなくインラインボックスが下に揃っています。

どうやら画像(img要素)や inline-block のように、要素が高さ( height )を持っていると、そちらの数値のほうが優先されるようです

これは、table-cell 要素でも同じで、inline-block の height があればそちらの高さを優先します。


インラインに設定したときのことをまとめますと、次のような感じです。

  • 基本はフォントや line-height が影響する
  • inline-block で height があるとき、そちらを優先する

なんだか余計こんがらがった気もしますが、inline-block で高さが指定されている時は、揃える基準が変わるので気をつけたほうがいいようです。

和文での中央揃いが難しい(middleで真ん中に揃わない)

もうひとつ困ったことが、和文での中央揃えです。

vertical-align を使う場面としては、挿入した画像やアイコンを真ん中に揃える時に使うこともあると思います。

この時、単純に vertical-align に middle(中間という意味)を指定すれば、英文ならばちょど良い位置に揃えてくれます。

ですが、和文では話が変わります。ちょっとズレているように見えるのです。

サンプルとして、まず中心が分かりやすいアイコンのようなものをCSSで作りました。

それを次のようにテキストの前に配置します。

<div> xテスト(指定なし)</div>
<div> xテスト(middle)</div>
div {
    background: linear-gradient(
                  rgba( 0, 102, 255, 0.2 ) 25%,
                  rgba( 0, 102, 255, 0.4 ) 25%,
                  rgba( 0, 102, 255, 0.4 ) 50%,
                  rgba( 0, 102, 255, 0.6 ) 50%,
                  rgba( 0, 102, 255, 0.6 ) 75%,
                  rgba( 0, 102, 255, 0.2 ) 75%
                );
    height: 2em;
    line-height: 2;
    margin: 0.5em 0;
}
div::before {
    border: 0.5em solid #fff;
    border-bottom-color: #f00;
    border-top-color: #f00;
    content: "";
    display: inline-block;
    height: 0;
    opacity: 0.5;
    width: 0;
}
div:nth-child( 2 )::before {
    vertical-align: middle;
}

これらを表示させたものが、こちらの画像です。

中央揃えで、こっと真ん中からズレている画像

背景色は四色に別れています。line-height が2なので、ちょうど行とフォントと行間の余白、それとフォントの真ん中のラインを見分けやすくしています。

これを見ての通り、中心から少しズレています

なぜズレるかと言えば、本来 middle は「小文字の" x "」の中間の交差点の位置を middle としています。

欧文ではこの「小文字の" x "」が基準点になっているため、この中心を「中間」としても文章全体に違和感は生じません。

ですが平仮名や漢字といった和文の場合、だいたいは正方形の枠に収まるように書きます。つまり字の中心が違うのです

さらに言えば、フォントのデザインによってもこれらは変わってきます。先ほどの画像はズレが分かりやすい「Noto Sans CJK JP」なのですが、それとは違うフォントを指定したところアイコンの位置が変わっています(下の画像は左が baseline で、右が middle です)>

フォントの種類を変えてテストしてみた画像

もうこうなってきたら、どの和文フォントでも共通する正確な中間ラインの取り方なんて不可能だと思います

でも、まあ、中間に近ければ「真ん中だ」と目が勝手に錯覚してくれますので、だいたい真ん中に近ければよいかな~と思っています(笑)

それで設定方法なのですが、やり方自体はいろいろあるのですが結局は vertical-align に相対値である em を指定するのが1番良いように感じます

例えば、先ほどの三種類のフォントで設定してみたところ、次のような感じです。

div:before {
    vertical-align: -0.1em;
}

中央近くで揃えれるように調整した画像

数値はアイコンや画像の大きさによって変わりますが、em の場合フォントの大きさが変わってもアイコンの位置のズレがあまりありません。

まとめ

いろいろやってみた結果は以上です。

今回いろいろ試してみて vertical-align がどんなものかというのが、何となく分かったような気がします(逆にこんがらがった可能性もありますが…笑)。

位置の違い、とくに真ん中配置とかは非常に細かいことなんですけど、迷う時には迷ってしまうんですよね、わたしのように。

そんな方に対して、この記事が何かの参考になれば、とても嬉しいです。

スポンサーリンク

*1:または「最もline-height(ラインボックス)が大きい要素の baseline で揃える」とも言えます。