Vertical-Align,你應該知道的一切

咱們聊聊vertical-align。這個屬性主要目的用於將相鄰的文本與元素對齊。而實際上,verticle-algin能夠在不一樣上下文中靈活地對齊元素,以及進行細粒度的控制,沒必要知道元素的大小。元素仍然在文檔流中,於是其餘元素能夠根據它們大小的變化進行相應的調整。一個有用的例子就是居中圖標與旁邊的文本。css

Vertical-Align是個怪物

 

但是,vertical-align有時候也很難搞,常常致使困惑。好像有什麼神祕的規則在起做用。好比,咱們改變了某個元素的vertical-align而它的對齊方式卻並未改變,反卻是同一行的其餘元素的對齊方式變了!我時不時地仍然會掉到vertical-align的坑裏,絕望無助。ide

遺憾的是,關於這方面的資料大都講得很膚淺。尤爲是針對佈局的狀況。不少文章概念錯亂,試圖把元素中的一切都垂直對齊。它們介紹了這個屬性的基本概念,解釋了簡單狀況下元素的對齊,卻沒涉及真正棘手的部分。佈局

所以,我給本身設定了一個目標:完全摸清vertical-align的行爲。而後我就死啃W3C的CSS規範,同時也嘗試了一些例子。最終寫出了這篇文章。字體

好,下面咱們就開始吧。ui

對哪些元素可使用Vertical-Align

 

vertical-align用於對齊行內元素。所謂行內元素,即display屬性值爲下列之一的元素:spa

  • inline對象

  • inline-blockelement

  • inline-table (本文未涉及)文檔

其中,行內元素(inline element)就是包含文本的標籤。it

行內塊元素(inline-block element),顧名思義,就是位於行內的塊元素。能夠有寬度和高度(能夠由其內容決定),也能夠有內邊距、邊框和外邊距。

行內級元素會相互挨着排成行。若是一行排不下,就會在下方再建一行。全部行都會建立所謂的行盒子,行盒子裝着本身行中的全部內容。內容的高度不一樣,行盒子的高度也不一樣。在下面的示意圖中,行盒子的頂部和底部用紅色點線表示。

這些行盒子限定了咱們能夠影響的範圍。在行盒子內部,能夠經過vertical-align來對齊個別元素。那麼,相對於什麼來對齊元素呢?

基線與外邊界

 

垂直對齊最重要的參考點,就是相關元素基線。某些狀況下,行盒子的上下外邊界也會成爲參考點。下面咱們就來看一看相關元素類型的基線和外邊界。

行內元素

這裏有三行文本緊挨着。紅線表示行高的頂邊和底邊,綠線表示字體高度,藍線表示基線。左邊這一行,行高與字體高度相同,所以上下方的紅色和綠線重疊在了一塊兒。中間一行,行高是font-size的兩倍。右邊一行,行高爲font-size的一半。

行內元素的外邊界與本身行高的上、下邊對齊。行高比font-size小不小並不重要。所以上圖中紅線同時也就表示外邊界。

行內元素的基線是字符剛好位於其上的那條線,也就是圖中的藍線。大體來講,基線老是穿過字體高度一半如下的某一點。能夠參考W3C規範中詳細的定義。

行內塊元素

從左到右:包含流內內容(「c」)的行內塊、包含流內內容且設置了溢出(overflow: hidden)的行內塊和未包含流內內容(但內容區有高度)的行內塊。紅線表示外邊距的邊界,黃色是邊框,綠色的內邊距,藍色是內容區,藍線是每一個行內塊元素的基線。

行內塊元素的外邊界即其外邊距盒子的上、下兩邊,也就是圖中的紅線。

行內塊元素的基線取決於元素是否包含流內內容:

  • 有流內內容的行內塊元素,基線就是正常流中最後內容元素的基線(左)。這個最後元素的基線是按照它本身的規則找到的。

  • 有流內內容但overflow屬性值不是visible的行內塊元素,基線就是外邊距盒子的底邊(中)。也就是與行內塊元素的下外邊界重合。

  • 沒有流內內容的行內塊元素,基線一樣是外邊距盒子的底邊(右)。

     

行盒子

 

這張圖前面出現過。但此次咱們畫出了行盒子的文本盒子的上、下邊(綠色,下面詳細介紹)還有基線(藍色)。同時,還用灰色背景表示了文本元素的區域。

行盒子的頂邊與該行中最頂部元素的頂邊重合,底邊與該行中最底部元素的底邊重合。所以圖中的紅線表示的就是行盒子。

行盒子的基線是個變量:

CSS 2.1沒有定義行盒子的基線。

 

在使用vertical-align時這一塊應該是最使人困惑的了。也就是說,基線畫在哪裏須要知足不少條件,好比要符合vertical-align指定的條件,同時還要保證行盒子高度最小。這是個自由變量。

由於行盒子的基線並不可見,因此有時候不容易肯定它的位置。但實際上有個簡單的辦法能夠令其可見。只要在相關行的開頭加上一個字母,好比上圖中開頭的「x」便可。若是這個字母沒有被設置對齊,那麼它默認就位於基線之上。

圍繞基線的是行盒子中的文本盒子。能夠簡單地把文本盒子當作行盒子內部未經對齊的行內元素。文本盒子的高度等於其父元素的font-size。所以,文本盒子只是用來盛放未經格式化的文本的。上圖中的綠線表示的就是文本盒子。因爲文本盒子與基線關聯,因此基線移動它也會跟着移動。(W3C規範裏稱這個文本盒子爲strut。)

終於把最難的部分講完了。如今,咱們已經知道了對齊相關的一切要素。下面簡單總結一下最重要的兩點。

  • 有一個區域叫行盒子。行盒子中的內容能夠垂直對齊。行盒子有基線文本盒子,還有上邊和下邊。

  • 還有行內元素,也就是能夠被對齊的對象。行內元素有基線,以及上邊和下邊。

 

Vertical-Align的值

 

使用vertical-align,前面提到的參考點就會按照某種關係被設置好。

對齊行內元素的基線和行盒子的基線

  • baseline:元素基線與行盒子基線重合。

  • sub:元素基線移動至行盒子基線下方。

  • super:元素基線移動至行盒子基線上方。

  • <百分比值>:元素基線相對於行盒子基線向上或向下移動,移動距離等於line-height的百分比。

  • <長度值>:元素基線相對於行盒子基線向上或向下移動指定的距離。

相對於行盒子的基線對齊元素的外邊界

  • middle:元素上、下邊的中點與行盒子基線加上x-height的一半對齊。

相對於行盒子的文本盒子對齊元素的外邊界

 

還有兩種狀況是相對於行盒子的基線對齊,由於文本盒子的位置由行盒子的基線決定。

 

  • text-top:元素的頂邊與行盒子的文本盒子的頂邊對齊。

  • text-bottom:元素的底邊與行盒子的文本盒子的底邊對齊。

相對於行盒子的外邊界對齊元素的外邊界

  • top:元素的頂邊與行盒子的頂邊對齊。

  • bottom:元素的底邊與行盒子的底邊對齊。

固然,正式的定義在W3C的規範裏。

爲什麼Vertical-Align的行爲如此乖張

 

下面咱們看看在某些狀況下的垂直對齊。特別是一些容易出錯的狀況。

居中圖標

有一個問題一直困擾着我。有一個圖標,我想讓它與一行文本垂直居中。若是隻應用vertical-align: middle好像不行,好比這個例子:

<span class="icon middle"></span>

Centered?

 

 

<span class="icon middle"></span>

<span>Centered!</span>

 

<style type="text/css">

  .icon display: inline-block;

            /* size, color, etc. */ }

 

  .middle vertical-align: middle}

</style>

仍是同一個例子,只不過此次多了一些輔助線:

此次能夠看清問題所在了。由於左側的狀況是文本沒對齊,而是仍然位於基線之上。應用vertical-align: middle,實際上會致使圖標中心與不出頭小寫字母的中心(x-height的一半)對齊,因此出頭的字母會在上方突出出來。

右側,仍然是對齊整個字體區的垂直中點。結果文本基線稍稍向下移動了一點,因而就實現了文本與圖標完美對齊。

行盒子基線的移動

這是使用vertical-align時一個常見的坑:行盒子基線的位置會受到其中全部元素的影響。假設一個元素採用的對齊方式會致使行盒子移動。因爲大多數垂直對齊(除top和bottom外),都相對於基線計算,所以這會致使該行全部其餘元素從新調整位置。

下面是幾個例子。

  • 若是行內有一個很高的元素,這個元素上方和下方都沒有空間了,此時要與行盒子的基線對齊,就必須讓它移動。矮盒子是vertical-align: baseline。左側的高盒子是vertical-align: text-bottom,而右側的高盒子是vertical-algin: 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的其餘值對齊一個較高的元素時,也會出現一樣的現象。

 

  • 即便設置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>

 

  • 把兩個較大的元素放在一行並垂直對齊它們,基線也會移動以匹配兩種對齊。而後,行的高度會調整(左)。再增長一個元素,但該元素對齊方式決定了它不會超出行盒子的邊界,因此行盒子不會調整(中)。若是新增的元素會超出行盒子的邊界,那麼行盒子的高度和基線就會再次調整。在這例子中,前兩個盒子向下移動了(右)。

<!-- left mark-up -->

<span class="tall-box text-bottom"></span>

<span class="tall-box text-top"></span>

 

<!-- middle mark-up -->

<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-align100%}

</style>

 

行內元素下面可能會有一個小間隙

 

看看這個例子:對列表元素的li應用vertical-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>

咱們看到,列表項位於基線上。基線下面有一個小間隙,用於文本的下伸部分。怎麼辦?只要把基線向上移開一點就好了,好比用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>

有文本內容的行內塊不會出現這種狀況,由於內容已經把基線向上移了。

行內元素間的間隙會破壞佈局

這主要是行內元素自己的問題。因爲vertical-align必然會遇到行內元素,因此有必要了解一下。

在前面列表項的例子中也能夠看到這個間隙。這個間隙來自你的標記中行內元素間的空白。行內元素間的全部空白會摺疊爲一個。若是咱們要經過width: 50%實現並排放兩個行內元素,那這個空白就會成爲障礙。由於一行放不下兩個50%再加一個空白,結果就會折行(左)。要刪除這個間隙,須要在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;

          width50%}

</style>

 

Vertical-Align揭祕

 

好了,就這些。一旦瞭解了規則,就沒有那麼複雜了。若是vertical-align沒有達到效果,只要問下面的問題就能找到癥結所在:

  • 行盒子的基線和上、下邊界在哪兒?

  • 行內元素的基線和上、下邊界在哪兒?

據此就能夠找到問題的解決方案。

相關文章
相關標籤/搜索