メインコンテンツへ移動

vertical-align 徹底解説

無料2017-08-13#CSS#line-box#text-box#vertical-align无效#vertical-align原理#vertical-align规范#vertical-aligin计算方式

CSS 仕様と組み合わせて vertical-align を深く理解し、様々な奇妙な隙間を説明する

はじめに

本文の第一部分は Vertical-Align: All You Need To Know から翻訳したもので、以前 [CSS 上下左右中央揃え](/articles/css 上下左右中央揃え/) の参考資料部分で言及した翻訳待ちの記事です

残りの部分は原文のテクニック总结

一.訳文

.top{display:inline-block;vertical-align:top}.bottom{display:inline-block;vertical-align:bottom}.middle{display:inline-block;vertical-align:middle}.baseline{display:inline-block;vertical-align:baseline}.text-top{display:inline-block;vertical-align:text-top}.text-bottom{display:inline-block;vertical-align:text-bottom}.sub{display:inline-block;vertical-align:sub}.super{display:inline-block;vertical-align:super}strong{font-weight:400}figure{line-height:1;overflow:visible}figure ul,figure ol{margin:0 !important;;padding:0 !important;}figure.center{text-align:center}figure.bg-grey{background:#f0f0f0;padding:1em}figure .center{text-align:center;display:inline-block;width:100%}figure+pre{margin-top:1em}figure *+*{margin-top:0}figure figcaption{width:100%;margin:0;margin-top:1em;font-style:italic;font-size:.8em}figure .bg-grey{background:#d3d3d3}figure .bg-green{background:#c1cd89}figure .bg-yellow{background:#fcdb9a}figure .bg-blue{background:#8ab3bf}figure .border-grey{border:1px solid #d3d3d3}figure .font{white-space:nowrap;line-height:1}figure .font.small{font-size:.6666em}figure .font.smaller{font-size:.3333em}figure .font.large{font-size:1.5em}figure .font.larger{font-size:3em}figure .font.tall-line-height{line-height:2}figure .font.short-line-height{line-height:.5}figure .font.color-grey{color:#d3d3d3}figure .box{min-width:1em;min-height:1em}figure .box.shorter{min-height:.25em}figure .box.shorter.quad{min-width:.25em}figure .box.short{min-height:.5em}figure .box.short.quad{min-width:.5em}figure .box.tall{height:2em}figure .box.tall.quad{width:2em}figure .box.taller{height:4em}figure .box.taller.quad{width:4em}figure .box.quad.max-third-width{max-width:30%}figure .inline-overlay{display:inline-block;width:100%;margin-right:-100%;position:relative;z-index:10}figure .line{display:inline-block;width:100%;margin-right:-100%;position:relative;z-index:10;border-top:1px solid #000}figure .line.dashed{border-style:dashed}figure .line.dotted{border-style:dotted}figure .line.grey{border-color:#d3d3d3}figure .line.red{border-color:red}figure .line.blue{border-color:#00f}figure .line.green{border-color:#32cd32}figure .line.orange{border-color:#daa520}figure .show-box-model{background:#c1cd89;border-color:#fcdb9a}figure .show-box-model>.show-box-model-content{background:#8ab3bf;display:block;min-width:100%;min-height:100%} .columns.no-break>* { margin-right: 2.5%; width: 47.5% !important; display: inline-block; margin-top: 0; } .columns.no-break.thirds>* { margin-right: 2.5%; width: 30% !important; display: inline-block; margin-left: 0; }

並んで表示される要素を垂直に揃える必要があることがよくあります

CSS はいくつかの選択肢を提供します。時には float で解決し、時には position: absolute を使い、時には手動で marginpadding を追加するような汚い方法さえ使います。私はこれらの方法があまり好きではありません。フロートはそれらをトップ揃えにするだけで、手動でクリアする必要があります(フロートの影響)。絶対位置指定はいくつかの要素を標準ドキュメントフローから外し、周囲の要素に影響を与えられなくします。そして最も小さな変更でさえ固定された marginpadding を破壊します

しかし、もう一つの役割があります:vertical-align です。私はこれをより信頼できると思います。技術的には、vertical-align でレイアウトを実装するのは hack です。なぜならこれはレイアウトのために設計されたものではなく、テキストとその隣の要素を整列させるためのものだからです。しかし、vertical-align で異なる環境で柔軟かつ細粒度(fine-grained)に要素を整列させることもできます。要素のサイズを知る必要がなく、要素は依然として標準ドキュメントフロー中にあり、他の要素はそのサイズ変化に反応できます。これらの利点により、価値ある選択肢となりました

vertical-align の気まぐれ

しかし vertical-align は時々本当に厄介で、使うと挫折感を覚えます。神秘的なルールがいくつかあるようです。例えば、要素の vertical-align を変更しても自分自身の整列方式が変わらず、同じ行の他の要素(の整列方式)が変わることに遭遇するかもしれません!今でも時々これらの暗い隅に迷い込み、狂気させられます(tearing my hair)

不幸なことに、ほとんどの関連リソースは浅すぎます。特に vertical-align でレイアウトを実装したい時。彼らは要素内のすべてのものを垂直に揃えようとする誤った考えに焦点を当て、属性の基本的な紹介を行い、非常にシンプルなシナリオでの要素の整列方式を説明しますが、テクニック的な部分は説明しません

そこで、私は一労永逸に vertical-align の動作を明確にする目標を自分に課し、W3C の CSS 仕様 を深く掘り下げ、いくつかの例を試して終わりました。最終成果が本文です

では、ゲームルールから始めましょう

vertical-align の依存項

vertical-align はインラインレベル(inline-level)要素を整列させるために使用されます。つまり、display 属性の計算値が以下の場合です:

  • inline

  • inline-block

  • inline-table(本文では考慮しません)

インライン要素(inline elements)は基本タグで囲まれたテキストです

インラ���ン - ブロック要素(inline-block elements)はその名の通りです:インラインで生きるブロック要素(block elements living inline)。それらは widthheight(またはそのコンテンツによって決定される可能性あり)と paddingborder 及び margin を持つことができます

インラインレベル要素(inline-level elements)は一行中で一つずつ並び、現在の行に入りきらなくなると、その下に新しい行を作成します。これらすべての行はいわゆる行ボックス(line box)を持ち、その行のすべてのコンテンツを包みます。異なるサイズのコンテンツは高さの異なる行ボックスを意味します。下図で行ボックスの上下境界は赤線で示されています:

A tall in a line of text.
A short in a line of text.
This can happen.

行ボックスは私たちのコンテキストです(the line boxes trace out the field we are playing on)。これらの行ボックス中の vertical-align 属性が各要素を整列させる責任を負います。では、要素の整列とは一体どういうことでしょうか?

baseline と outer edge

垂直整列で最も重要な参照点は関連要素の baseline です。某些情况下、要素の包みボックスの頂辺と底辺も重要です。各種類の要素の baseline と outer edge がどこにあるか一緒に見てみましょう:

インライン要素

aA? qQ

-->

aA? qQ
<!--

-->

aA? qQ

3 行の並列したテキストが見えます。行高の頂辺と底辺は赤線で示され、フォントの高さは緑線、baseline は青線です。左のテキストの行高は font-size と同じに設定され、緑線と赤線が重合しました。中央のテキストの行高は font-size の 2 倍です。右の行高は font-size の半分です

インライン要素の outer edge はその行高の頂辺と底辺と揃います。行高がフォントの高さより小さい場合は問題ありません。したがって、outer edge は上図中の赤線です

インライン要素の baseline は文字が座っている線です(baseline is the line, the characters are sitting on)。つまり図中の青線です。理解しにくいのは、baseline が時々フォントの高さの下方にあることです。W3C 仕様の 詳細定義 を参照

インライン - ブロック要素

c

-->

c
<!--

-->

左から右へ順に:フロー内(in-flow)コンテンツ(あの「c」)を含むインライン - ブロック要素、フロー内コンテンツと overflow: hidden を含むインライン - ブロック要素、フロー内コンテンツを含まない(しかしコンテンツエリアは高さを持つ)インライン - ブロック要素です。margin の境界は赤線で示され、border は黄色、padding は緑色、コンテンツエリアは青色です。各インライン - ブロック要素の baseline は青線で示されています

インライン - ブロック要素の outer edge はその margin-box の頂辺と底辺です。つまり図中の赤線です

インライン - ブロック要素の baseline は要素がフロー内コンテンツを含むかどうかに依存します:

  • フロー内コンテンツを含む場合、インライン - ブロック要素の baseline は通常フロー中の最後のコンテンツ要素の baseline です(左の例)。最後の要素の baseline はそれ自身のルールに基づいて決定されます

  • フロー内コンテンツを含むが計算値が非 visibleoverflow 属性を持つ場合、baseline は margin-box の底辺です(中央の例)。したがって、それはインライン - ブロック要素の底辺と同じです

  • フロー内コンテンツを含まない場合、baseline も margin-box の底辺です(右の例)

行ボックス

x This can happen.

上図では、行ボックスのテキストボックス(詳細は後述)の頂辺と底辺を緑色で描き、baseline は青線のまま、テキスト要素に灰色の背景を設定してハイライトマークしました

行ボックスの頂辺はその行の最も高い要素の頂辺と揃い、底辺はその行の最も低い要素の底辺と揃います。上図で赤線で示された部分です

行ボックスの baseline は可変です:

CSS 2.1 does not define the position of the line box's baseline. — the W3C Specs

これは vertical-align を使用する時に最も人を混乱させる部分かもしれません。つまり、baseline をどこに置くかは他のすべての条件を満たす必要があります。例えば vertical-align と行ボックスの高さを最小にすることです。それは方程式中の自由パラメータです

行ボックスの baseline は見えないため、どこにあるか直観的に見ることはできません。しかし簡単に可視化できます。疑問のある行の先頭に文字を追加するだけです。図に追加した「x」のように。この文字が何らかの方法で整列されていない場合、デフォルトで baseline に座ります

baseline の周囲で、行ボックスはテキストボックス(text box)と呼ばれるものを含みます。テキストボックスは整列方式のない行ボックス中のインライン要素と簡単にみなせます。その高さはその親要素の font-size に等しいです。したがって、テキストボックスは行ボックス中でフォーマットされていないテキストのみを包みます。上図で緑線で示されています。このテキストボックスは baseline に縛られているため、baseline が動く時に一緒に動きます(注:このテキストボックスは W3C 仕様で strut と呼ばれます)

これが最も難しい部分でした。今、私たちは根底まで知りました。最も重要な数点を素早くまとめましょう:

  • 行ボックスと呼ばれる領域があります。垂直整列が発生する場所です。それは baseline、テキストボックス及び頂辺底辺を持ちます

  • インラインレベル要素は整列されるものです。それらは baseline と頂辺底辺を持ちます

vertical-align の値

上記の参照点とインラインレベル要素に特定の関連を設定するために vertical-align を使用します

要素の baseline を行ボックス baseline に対して整列

x baseline sub super -50% +10px
  • baseline:要素の baseline は行ボックスの baseline と正確に重合します

  • sub:要素の baseline を行ボックス baseline の下方に移動します

  • super:要素の baseline を行ボックスの baseline の上方に移動します

  • <percentage>:要素の baseline を行ボックスの baseline に対して line-height の百分比で移動します

  • <length>: 要素の baseline を行ボックスの baseline に対して絶対長さで移動します

要素の outer edge を行ボックス baseline に対して整列

x middle
  • middle:要素の頂辺底辺の中点を行ボックスの baseline に x-height の半分を加えたものと揃えます

要素の outer edge を行ボックスのテキストボックスに対して整列

x text-top text-bottom
  • text-top:要素の頂辺を行ボックスのテキストボックスの頂辺と揃えます

  • text-bottom:要素の底辺を行ボックスのテキストボックスの底辺と揃えます

要素の outer edge を行ボックスの outer edge に対して整列

x top bottom
  • top:要素の頂辺を行ボックスの頂辺と揃えます

  • bottom:要素の底辺を行ボックスの底辺と揃えます

もちろん、正式の定義 は W3C 仕様で全て見つかります

なぜ vertical-align の動作はこのようか

特定のシナリオでの垂直整列をより近くで見ることができます。特に失敗する可能性のあるシナリオです

中央揃えの小アイコン

私を悩ませる問題があります:小���なアイコンがあり、隣の一行情報と中央揃えにしたいです。小アイコンに vertical-align: middle を付けるだけでは中央揃え効果がそれほど満足できるものではありません。この例を見てください:

Centered?
Centered!
<!-- left mark-up -->
<span class="icon middle"></span>
Centered?

<!-- right mark-up -->
<span class="icon middle"></span>
<span class="middle">Centered!</span>

<style type="text/css">
  .icon   { display: inline-block;
            /* size, color, etc. */ }

  .middle { vertical-align: middle; }
</style>

ここにも同じ例がありますが、上で学んだ補助線をいくつか描きました:

x Centered?
x Centered!

これはいくつかの线索を明らかにします。左のテキストには整列方式がないため、baseline に座っています。実際、vertical-align: middle を設定して小方块を整列させる時、それを上伸部(ascender)のない小文字の中心位置(半个 x-height)に整列させています。したがって、上伸部を持つ文字は比較的上に表示されます

右の場合、フォントエリアの中点も垂直に整列させ、テキストの baseline を行ボックス baseline に対して少し下げて効果を実現します。結果はテキストと隣接する小アイコンが美しく中央揃えになります

行ボックス baseline の移動

これは vertical-align を使用する時の一般的な罠です:行ボックスの baseline はその行のすべての要素の影響を受けます。ある要素がこの方式で整列されていると仮定します(自身の baseline に対して整列)。行ボックスの baseline は移動しなければなりません。大多数の垂直整列(topbottom を除く)はその baseline に対して相対的であるため、その行の他のすべての要素も位置を調整します

いくつかの例:

  • 一行に高さのある要素が全体の高さを跨ぐ場合、vertical-align はそれに対して機能しません。その頂部の上と底部の下に移動できる空間がもうないからです。行ボックス baseline に対するその整列関係を満足させるために、行ボックス baseline は移動しなければなりません。矮い方块は vertical-align: baseline を持ちます。左側で、高い方块は text-bottom 整列です。右側は text-top 整列です。baseline が矮い盒子を一緒に連れて跳ね上がったことが発見できます
  <!-- left mark-up -->
  <span class="tall-box text-bottom"></span>
  <span class="short-box"></span>

  <!-- right mark-up -->
  <span class="tall-box text-top"></span>
  <span class="short-box"></span>

  <style type="text/css">
    .tall-box,
    .short-box   { display: inline-block;
                  /* size, color, etc. */ }

    .text-bottom { vertical-align: text-bottom; }
    .text-top    { vertical-align: text-top; }
  </style>

他の vertical-align 値で高い要素を整列する時にも同じ動作が発生します

  • vertical-alignbottom(左図)と top(右図)に設定しても baseline を移動します。これは奇妙です。baseline が全く関係ないからです
  <!-- left mark-up -->
  <span class="tall-box bottom"></span>
  <span class="short-box"></span>

  <!-- right mark-up -->
  <span class="tall-box top"></span>
  <span class="short-box"></span>

  <style type="text/css">
    .tall-box,
    .short-box { display: inline-block;
                 /* size, color, etc. */ }

    .bottom    { vertical-align: bottom; }
    .top       { vertical-align: top; }
  </style>
  • 一行に 2 つの大きな要素を置き、それらを垂直に整列すると baseline をそれらの整列方式を満足させる位置に移動し、行ボックスの高さも調整します(左図)。3 番目の要素を追加し、その整列方式が行ボックスの境界を超えない場合、行ボックスの高さも baseline の位置も影響しません(中図)。それが行ボックスの境界を超えた場合、行ボックスの高さと baseline は再び調整されます。この場合、最初の 2 つの方块は押し下げられます(右図)
  <!-- left mark-up -->
  <span class="tall-box text-bottom"></span>
  <span class="tall-box text-top"></span>

  <!-- mark-up in the middle -->
  <span class="tall-box text-bottom"></span>
  <span class="tall-box text-top"></span>
  <span class="tall-box middle"></span>

  <!-- right mark-up -->
  <span class="tall-box text-bottom"></span>
  <span class="tall-box text-top"></span>
  <span class="tall-box text-100up"></span>

  <style type="text/css">
    .tall-box    { display: inline-block;
                   /* size, color, etc. */ }

    .middle      { vertical-align: middle; }
    .text-top    { vertical-align: text-top; }
    .text-bottom { vertical-align: text-bottom; }
    .text-100up  { vertical-align: 100%; }
  </style>

インラインレベル要素の下方に小さな隙間がある可能性があります

この状況を見てください。リスト内の livertical-align する時に、よく遭遇します:

<ul>
  <li class="box"></li>
  <li class="box"></li>
  <li class="box"></li>
</ul>

<style type="text/css">
  .box { display: inline-block;
         /* size, color, etc. */ }
</style>

図に示すように、リスト項目は baseline に座っています。baseline の下方にはテキストの下延部(descender)を収容するための空間があり、隙間を造成します。解決策は?baseline をもう少し遠くに移動するだけです。例えば、vertical-align: middle でリスト項目を整列します:

<ul>
  <li class="box middle"></li>
  <li class="box middle"></li>
  <li class="box middle"></li>
</ul>

<style type="text/css">
  .box    { display: inline-block;
            /* size, color, etc. */ }

  .middle { vertical-align: middle; }
</style>

このシナリオはテキストコンテンツを含むインライン - ブロック要素には現れません。コンテンツはすでに baseline に移動されている ためです

インラインレベル要素間の隙間がレイアウトを破壊

これは主にインラインレベル要素自身の問題ですが、それらは vertical-align の依存項の一つであるため、はっきり理解しておくのが良いでしょう

前の例でもリスト項目間の隙間が見られました。隙間はマークアップコード(HTML/XML など)に現れるインライン要素間の空白文字から来ます。インライ���要素間のすべての空白文字は 1 つのスペースに統合されます。このスペースが邪魔をします。例えば 2 つのインライン要素を僅かに隣り合わせにし、両方に width: 50% を設定したい場合、2 つの 50% の要素と 1 つのスペースを収容する十分な空間がありません。したがって 2 行に拆分されてレイアウトを破壊します(左図)。隙間を除去するために、空白文字を除去する必要があります。例えば HTML コメントを使用します(右図)

50% wide
50% wide... and in next line
50% wide
50% wide
<!-- left mark-up -->
<div class="half">50% wide</div>
<div class="half">50% wide... and in next line</div>

<!-- right mark-up -->
   <div class="half">50% wide</div><!--
--><div class="half">50% wide</div>

<style type="text/css">
  .half { display: inline-block;
          width: 50%; }
</style>

vertical-align 揭秘

ええと、就是这样。ルールを知ればそれほど複雑ではありません。vertical-align が効果がない場合、これらの問題だけを考える必要があります:

  • 行ボックスの baseline と頂辺底辺はどこにあるか?

  • インラインレベル要素の baseline と頂辺底辺はどこにあるか?

これは問題の解決策を明らかにします

二.テクニック

1.行ボックスの baseline をどのように確定するか?

この行に下延部のない文字を追加します。一般習慣では x を追加します。文字の底部縁が行ボックス baseline の位置です

例えば:

.baseline:before {
    content: 'x';
}

2.行ボックスの境界をどのように確定するか?

上で言及した「要素の outer edge を行ボックスの outer edge に対して整列」を利用します:

.line-box-top {
    border-top: 1px dotted red;
    /* border-top を行ボックスの頂辺と重合させる */
    vertical-align: top;

    /* 幅を整行に満たす */
    display: inline-block;
    width: 100%;
    /* 空間を開け、コンテンツレイアウトに影響するのを避ける */
    margin-right: -100%;
    /* z を上げ、コンテンツに遮られるのを避ける */
    position: relative;
    z-index: 10;
}
/* .line-box-bottom もこれと類似 */

行ボックス境界を明確にしたい行の行首に追加します(margin-right: -100% を使用するため、最も左に置きます)

<span class="line-box-top"></span><span class="line-box-top"></span>

即可

3.テキストボックスの境界をどのように確定するか?

行ボックス境界を確定する方法と類似です。vertical-align: text-top;vertical-align: text-bottom; を利用します

誰に対して整列するか。そうすればこの「誰」を描くことができます

4.HTML コメントで空白文字を除去するテクニック

例えば:

<figure>
    <span class="large font">
        <span class="green dotted line text-top"> </span><!--
     --><span class="green dotted line text-bottom"> </span><!--
     --><span class="red dotted line top"> </span><!--
     --><span class="red dotted line bottom"> </span><!--
     --><span class="blue dotted line baseline"> </span><!--
     --><span class="font color-grey inline-overlay">x</span><!--
     --><span class="center">
            <span class="middle bg-grey">This</span>
            <span class="tall box bg-grey text-top"> </span>
            <span class="top bg-grey">can</span>
            <span class="tall box bg-grey text-bottom"> </span>
            <span class="bottom bg-grey">happen.</span>
        </span>
    </span>
</figure>

空白文字を除去すると同時に、タグのインデント形式を保留します。非常に面白いです

コメント

コメントはまだありません

コメントを書く