【譯】關於vertical-align你應知道的一切


原文地址:Vertical-Align: All You Need To Know

通常我們需要垂直對齊並排的元素。

CSS提供了一些可實現的方法:有時我用浮動float來解決,有時用position: absolute來解決,有時甚至是“骯臟”地手動添加的margin或padding。

我真的不喜歡這些解決方案。float只對齊元素的頂部,且需要手動清除浮動。絕對定位的元素脫離文檔流,所以他們不再影響周圍的元素。而用修補性的margin或padding打破了最細微變化的東西。

但這里還有一個選擇:vertical-align。我認為它值得我們更多地信任和使用。在技術上,使用vertical-align的布局是一種hack,因為vertical-align不是為這個目的(垂直對齊布局)發明的。它的存在,是用以對齊並排在一起的文本和元素。盡管如此,你還是可以在不同的上下文中,使用vertical-align靈活而精確地對齊相鄰元素。元素的大小不必是已知的。元素留在文檔流中,所以周圍的其他元素可以會根據這個元素受到的改變而做出反應。這使得vertical-align成為一個有價值的選擇。

 

vertical-align的特殊性

但是,vertical-align有時候很操蛋,它會令你抓狂,似乎它在使用中有一些神秘的規則。例如,你可能改變了元素的vertical-align,但沒有出現你想要的效果,但行中的其他元素卻被改變了!這時我就很想跑到黑暗的角落里撓牆,撕扯我的頭發。

不幸的是,大部分關於vertical-align的文章資源都有點淺,特別是關於使用vertical-align來布局的。他們經常誤解vertical-align,試圖用它垂直對齊一個容器內的所有元素。他們給vertical-align做基本的介紹,並解釋如何在非常簡單的情況下對齊元素,卻不解釋棘手的部分。

所以,我給自己設定了目標,希望一次說清垂直對齊的所有行為。我最終通過W3C的CSS規范和一些實例總結得出本文。

所以,讓我們來理清vertical-align游戲規則。

 

使用vertical-align的條件

vertical-align是用來對齊內聯級元素的。

設置為以下display屬性的元素,它們都被認為屬於內聯級元素。

inline,

inline-block or

inline-table (本文中不涉及此種情況)

inline內聯元素基本上是包裹文本的標簽。

inline-block內聯塊元素則如它們的名字所示:擁有內聯特性的塊元素。他們可以有width和height(可能是由自己的內容定義),以及padding、border和margin。

內聯級元素彼此緊挨着放在一行中。一旦有更多的元素被放置到當前行中,一個新的行將會在它下面創建。所有這些行有所謂的“行框”,行框中包含所有的內容。不同大小的內容意味着不同高度的行框。在下面的插圖中,行框的頂部和底部都是用紅線表示的。

行框(line box)勾勒出我們正在設計的區域(下文會詳細介紹“行框”的概念)。在行框中,元素的vertical-align屬性是負責垂直對齊的。那么,到底元素垂直對齊的參照物是什么?

參照物:父元素的基線和外邊緣

vertical-align與元素的基線息息相關。在某些情況下,元素的行框的頂部和底部邊緣也變得很重要。讓我們看看元素的基線和行框的外觀:

·內聯元素

此處,你可以看到三行並排的文本。行框的頂部和底部邊緣用紅線表示,字體的高度由綠線表示,基線由一條藍線表示。在左邊,有一個line-height設置為與字體font-size大小相同高度的文本,綠線和紅線重疊在一條線上。在中間,line-height是字體的兩倍大。在右邊,line-height是字體大小的一半大。

內聯元素(display:inline)的外邊緣與其行高的頂部和底部邊緣對齊,行高可以小於字體的高度。所以,行框就是上面的圖中的紅線。

內聯元素的基線是字符放置的位置線(字母x底部所在的水平線),即圖中的藍線。粗略地說,基線是在字體1/2高度的下面的某個地方。感興趣的可以看看W3C規范的詳細定義

·內聯塊元素

從左到右,你可以看到:在左邊,是一個內聯塊元素包含了一個流內內容(一個“C”);在中間,一個內聯塊元素包含了一個流內內容(也是一個“c”),元素屬性有overflow: hidden;在右邊,一個內聯塊元素包含了一個流外內容(但內容區域有一個高度)。(譯者注:流內的元素必須是普通文檔流(normal flow)中的元素,流外的元素必須是浮動或絕對定位的元素以及根元素。)margin的邊界是由紅線表示,border是橘黃色的,padding是綠色的和內容區域是藍色的。每個內聯塊元素的基線為一條藍色線。

內聯塊元素的外邊緣是其margin框的頂部和底部邊緣,即圖中的紅線。

內聯塊元素的基線取決它包含的內容是否在文檔流中:

  • 在流內內容的情況下,內聯塊元素的基線是正常流中最后一個內容元素的基線(左邊的例子)。對於這最后一個元素,它的基線是根據它自己的規則找到的。
  • 在流內內容但內聯塊元素有overflow:hidden屬性的情況下,基線是內聯塊元素margin框的底部邊緣(例如在中間)。
  • 在流外內容的情況下,基線是內聯塊元素margin框的底部邊緣(例如在右邊)。

·行框

你已經看到了上面的設定。這一次,我將在行框里的文本框頂部和底部畫上綠線,以及基線(藍色)。我還用灰色背景強調了該區域的文本元素。

該行框的頂部邊緣對齊該行中最頂部元素的頂部邊緣,底部邊緣對齊該行中的最底部元素的底部邊緣。如上圖中紅線所表示的盒子。

·行框的基線是可變的:

CSS 2.1沒有定義行框的基線位置。- W3C規范

當使用vertical-align時,基線放置在哪里可能是最令人疑惑的部分。它需要滿足vertical-align的值和行框的高度等所有條件。基線的位置猶如是方程中的一個自由參數。

行框的基線是看不見的,但你可以使它很容易看到。只要在文本行的開頭添加一個字符,像我增加了一個“X”的字母。如果這個字符不以任何方式對齊,它將默認地坐在基線上。

圍繞着行框的基線的部分(綠線),我們可以稱其為文本框。文本框可以簡單地被認為是行框內的內聯元素,沒有任何對齊。文本框的高度等於它的父元素的字體大小。因此,文本框只圍住了行框內的無格式文本。由於這個文本框是綁在基線上的,當基線移動時它將移動。(注:此文本框在W3C規范中稱為“strut(支柱)”)

好了,以上是最難的部分。現在,讓我們迅速總結一下上面的重點:

  • 有一個稱為行框的區域。這是垂直對齊發生的區域。它有一個基線,一個文本框和一個頂部和底部邊緣。
  • 有一些稱為內聯級元素的元素。它們都是會對齊的對象。他們有一個基線和一個頂部和底部邊緣。

 

vertical-align的值

它的值分為以下幾種對齊方式:

1)將元素的基線,參照父元素的基線對齊

baseline:元素的基線與父元素的基線對齊。

sub:元素的基線偏移到父元素的基線之下。

sup:元素的基線偏移到父元素的基線之上。

<percentage>:元素的基線相對於父元素的基線偏移了一個百分比(該百分比是對比元素自身的line-height計算得出)。

<length>:元素的基線相對於父元素的基線偏移了一個絕對長度。

2)將元素的中心點,參照父元素的基線對齊

middle:將元素的頂部和底部之間的中心點,對齊父元素的基線之上x-height的1/2之處(x-height為字母x的字符高度)。

3)將元素的外邊緣,參照父元素的文本框對齊

text-top:將元素的頂部邊緣,對齊到父元素的文本框的頂部邊緣。

text-bottom:將元素的底部邊緣,對齊到父元素的文本框的底部邊緣。

4)將元素的外邊緣,參照父元素行框的外邊緣對齊

top:元素的頂部邊緣對齊到父元素的頂部邊緣。

bottom:元素的底部邊緣對齊到父元素的底部邊緣。

當然更正式的定義可以參考W3C規范

 

為什么vertical-align會這樣呈現?

我們現在可以仔細看看以下幾種使用vertical-align有問題的情況:

1)垂直居中一個圖標

我們經常遇到這樣的需求,我有一個圖標,我想將它垂直居中於一行文本。只給圖標設置vertical-align: middle似乎並沒有出現令人滿意的效果。看一看這個例子:

<!-- 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>

我們畫了輔助線方便理解(上文中我們知道每種顏色的線代表什么)

這樣我們的答案更清晰了:在左邊,文本並沒有設置居中對齊,它位於基線上。原因是我們把圖標設置了vertical-align: middle,但文本並沒有設置垂直居中。所以,文本站在了基線上面,而圖標的中點對齊到父元素的基線之上1/2 x-height的位置。

在右邊,我們讓圖標和文字都設置了vertical-align: middle。文本的基線和圖標的中點都對齊到父元素的基線之上1/2 x-height的位置。

2)行框基線的移動

這是一個常見的陷阱,當使用vertical-align:行框的基線位置會被其內部的所有元素影響。如果一個容器內的元素是按以下其中一種方式排列的,那么它的行框的基線必須移動。

一些例子:

如果一行中有一個高個的元素占據了整行的高度,那么vertical-align對它沒有影響。它的頂部和底部沒有空間讓它移動。為了滿足行框基線的對齊方式,行框的基線必須移動。矮個元素設置了vertical-align: baseline。在左邊,高個元素設置了vertical-align: text-bottom。在右邊,高個元素設置了vertical-align: text-top。你可以看到右邊的基線跳起來了。

<!-- 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 為 bottom (左) 和 top (右),基線也會移動。

<!-- 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>

(左)將兩個元素放在一行中並設置vertical-align ,它們會使得行框的基線移動到符合它倆的對齊規則之處,然后行框的高度也會隨之調整。(中)添加第三個元素,不超越行框的邊緣,既不影響行框的高度,也不影響基線的位置。(右)添加第三個元素,如果它超出了行框的邊緣,行框的高度和基線調整。在這種情況下,我們的前兩個元素也會跟着發生變化。

<!-- 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>

3)內聯級元素底部的小間隙

看一看以下情況。這很常見,如果你嘗試垂直對齊列表中的元素。

<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>

正如你所看到的,列表項坐在基線上。下面的一點空間,是文本的基線以下預留的depth(在W3C規范中,一個字體的基線以上稱為characteristic height,基線以下稱為depth)。想要去掉這個depth空隙,有解決的辦法嗎?只要移動基線的位置就可以,例如通過設置列表項目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>

這種情況不會發生在含有文本內容的內聯塊元素中,因為內容已經將基線移動了。

4)內聯級元素之間的空隙打破了布局

這主要是內聯級元素本身的問題。但因為他們常使用垂直對齊,我們應該了解清楚這個問題。

在上面的示例中,我們可以看列表項之間的間隙。該間隙來自於在你的內聯元素標簽之間的空格white-space。在內聯元素之間的所有空格都被折疊成一個空間。例如,如果我們想並排放置兩個內聯元素,並給他們width:50%,這時就沒有足夠的空間放置兩個寬50%元的素和一個間隙。因此,它們會被分成兩行破壞了布局(左)。為了消除間隙,我們需要想辦法消除空格white-space,例如用HTML注釋(右)。

<!-- 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的揭秘。一旦你知道了規則,它就不會很復雜了。如果垂直對齊沒有表現出你要的效果,只需要問以下問題:

行框的基線以及頂部和底部邊緣在哪里?

內聯級元素的基線和頂部和底部邊緣在哪里?

這將是解決問題的方案。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM