1. 程式人生 > >CSS進階(8)—— 內聯元素的掌管者line-height和vertical-align(下)

CSS進階(8)—— 內聯元素的掌管者line-height和vertical-align(下)

  上一章主要講了line-height相關的知識,本章就來聊聊同樣無處不在的vertical-align。vertical-align和line-height一樣,都會影響元素在與水平流垂直方向上的表現,因此瞭解這兩個屬性,對於我們控制圖文在垂直方向上的表現有很大的幫助。這裡我用了"幫助",而不是必要,有人告訴我這本書不用一個字一個字看,現在看來確實如此,《CSS world》在某種程度上已經完全符合"鑽牛角尖"的氣質,但既然看了,就希望能把這個系列做完。

  依舊先放上內容摘要,按需觀看。

1.vertical-align的五類屬性

2.跟x字母打交道的vertical-align:baseline/middle

3.基於行框盒子上下邊緣對齊的top/bottom屬性

4.從瞭解到棄用:vertical-align的文字屬性類

5.簡單瞭解vertical-align的上標下標類屬性

6.vertical-align被忽略的實用數值屬性

7.baseline在inline-block元素中的詭異表現

 

1.vertical-align的五類屬性

  拋開inherit這類全域性屬性不談,個人把vertical-align分成五類,作者將第一類和第二類總結成線類。

  (1)跟x字母打交道的線類:baseline/middle

  (2)基於行框盒子邊緣的線類:top/bottom

  (3)跟父級基線相關的文字類:text-top/text-bottom

  (4)常用於公式的上標下標類:super/sub

  (5)具體數值類:2px/2em/20%等

  通常情況下,內聯元素預設都是沿著字母x的下邊緣對齊的,也就是vertical-align的預設值是baseline。但對於圖片等替換元素,往往使用元素本身的下邊緣作為基線,這一點在過去的簡陋佈局中顯得非常好用,二十年前的網頁你甚至都不需要會寫CSS就可以讓讀者正常瀏覽網站內容,但是如今這些"好用的"特點會給我們的CSS佈局帶來很多不便之處。下面我們通過實戰來一一測試這些屬性的表現以及利用這些表現實現一些佈局方式。

2.跟x字母打交道的vertical-align:baseline/middle

  前面說到了,vertical-align的預設值是baseline,也就是字母x的下邊緣,為了更好的看清x的下邊緣在哪裡,我們需要藉助最常用的替換元素——圖片。圖片的下邊緣通常為元素本身,我們來看字母x和圖片都基於baseline對齊會有什麼表現吧。

<div>
	<span>字母x</span>
	<img src="../小和尚.jpg">
</div>
<style>
	
</style>

  可以看到,表現結果跟理論相同,x下邊緣與圖片下邊緣完全持平,那麼為什麼中文"字母"的下邊緣沒有和x下邊緣對齊呢?沒為什麼,大部分中文和部分字母的下邊緣就是低於baseline的,別問,問就是不知道。同時,你會發現,圖片的下邊緣會有4px的空隙,導致最終容器的高度多了4px,很多人第一反應就是甩鍋中文,因為中文看起來比字母x大一些,低一些,然而就算你把span標籤刪除了依舊會多出這4個畫素。那麼多出的4px是哪裡來的呢?這裡還要請出vertical-align的好朋友line-height一起來解釋這個問題。

  首先line-height的預設值是normal,這個值是根據font-size和font-family計算得到的,得到的值一般會大於字母x的高度,由於高度多出來的部分由line-height計算後在文字上下均勻分佈,因此你可以理解為多出來的4px是baseline到文字下邊緣的距離。因此,要解決這多出來的4px其實很簡單,修改圖片的vertical-align即可,如,讓他基於字母x的中點對齊。當然這只是理論上,你可以根據實際需求解決這個問題。

  說完了baseline,再來聊聊middle。我不敢說很多人,我自己之前在理解vertical-align:middle的時候,認為CSS在父容器中間找了一條中線,然後讓所有的圖文基於這條中線均勻分佈。事實上,這樣理解的壞處是,你會認為vertical-align需要加在父容器上,事實上vertical-align只在兩類元素內生效,就是內聯元素和table-cell元素。換句話說,vertical-align屬性只能作用在display計算值為inline、inline-block、inline-table或table-cell元素上。需要注意的是,浮動,絕對定位等讓元素塊化的操作也會讓vertical-align失效。瞭解了vertical-align的生效範圍後,我們來看看如何讓內聯元素在垂直方向上居中吧。依舊是剛才的例子,我們想讓圖片在固定高度的容器裡用vertical-align:middle屬性垂直居中。

<div>
	<span>字母x</span>
	<img src="../小和尚.jpg">
</div>
<style>
	div{
		height: 400px;
		background: rgba(0,0,0,0.1);
		text-align: center;
	}
	img{
		vertical-align: middle;
	}
</style>

  結果似乎不盡如人意,圖片並沒有垂直居中,為什麼會這樣呢?其實答案已經很明顯了,vertical-align:middle屬性已經生效了,在由span和img生成行框盒子中,圖片已經基於字母x的中點垂直居中了,那麼,怎麼讓圖片在父級容器中居中呢?這裡又要請到好朋友line-height的幫助了,只要讓line-height的值等於父容器的高度即可,當然,為了簡化程式碼,我們可以去掉height的申明,讓元素保持流的特性,自動撐開容器高度。

  這裡圖片已經完美垂直居中了,但對於文字,可能會有一定的偏差,因為字母x的中點和許多文字的實際中點會有所偏差,這個居中屬性在文字偏大的時候就顯得明顯偏下或偏上了。因此在實際使用的過程中,不要盲目迷信vertical-align的文字居中能力。 

3.基於行框盒子上下邊緣對齊的top/bottom屬性

  vertical-align:top;表示當前內聯元素的頂部在垂直上邊緣對齊。  在table-cell中表示元素底padding邊緣和表格行的頂部對齊。這裡我們只討論內聯元素。

<div>
	<span style="font-size: 14px">14px</span>
	<span style="font-size: 16px">16px</span>
	<span style="font-size: 18px">18px</span>
	<span style="font-size: 20px">字母x</span>
	<img src="../小和尚.jpg">
</div>
<style>
	div{
		height: 400px;
		background: rgba(0,0,0,0.1);
	}
	span{
		vertical-align: bottom;
	}
	img{
		vertical-align: bottom;
	}
</style>

  需要注意的是,內聯元素的上下邊緣對齊的邊緣是行框盒子的邊緣,不要混淆理解成了父級容器的邊緣。

4.從瞭解到棄用:vertical-align的文字屬性類

  當你深入理解了這個屬性之後,你就會發現這個屬性很難有什麼軟用。(這句話寫在開頭是為了讓你少鑽點牛角尖)

  作者在給vertical-align屬性分類的時候,將baseline/middle/top/bottom分為一類,其實都是基於行框盒子進行劃分的,只是個人由其表現差異性又細分成了兩類。而文字屬性類text-top/text-bottom在垂直方向佈局的時候則和行框盒子沒有多大關係了。

  vertical-align:text-top 表示盒子的頂部和父級應有內容區域的頂部對齊。

  vertical-align:text-bottom 表示盒子的底部和父級應有內容區域的底部對齊。

  內容區域指的是在預設狀態下用滑鼠選中文字時的背景藍色區域,這裡說的父級應有的內容區域指的是根據父級的font-size和font-family計算得到的內容區域。

  有興趣的可以參考原文demo。這裡就不深究這個看不到前途的屬性了。

5.簡單瞭解vertical-align的上標下標類屬性

  HTML裡有兩個標籤,<sup>上標,和<sub>下標

 <sup>對應的預設vertical-align:super

 <sub>對應的預設vertical-align:sub

 這兩個屬性無需多做說明,只需看一下他的具體效果即可。

<div>
	H<sub>2</sub>O<sup>[1]</sup>
</div>
<div>[1]:H<sub>2</sub>O是水的分子式</div>

  基本上這兩個屬性的唯一作用也就體現在他的名稱上了,平時一般都用不到,在公式計算中會比較常用。所以簡單瞭解即可。

6.vertical-align被忽略的實用數值屬性

  作者在原文中嘲諷"很多即使工作很多年的前端開發人員,可能不知道vertical-align的屬性值支援數值,更不知道支援負值",這著實讓他感到意外,沒錯我就是那個可能過一萬年都不會去知道這個值的程式設計師。在說明這個屬性的好處之前,先來看一個利用vertical-align“垂直居中”元素的例子。

<div style="line-height: 150px;">
	<span style="vertical-align: middle;font-size: 50px">我想垂直居中,卻有些偏下</span>
    <img src="../小和尚.jpg" style="vertical-align: middle;width: 50px;height: 50px">
</div>

  從結果上來看,由於中文相對於x的middle表現的總體偏下,在文字偏大的時候這個問題就表現得尤為明顯了,然而圖片在這個時候表現得又比文字要好,如果是文字+圖示(icon)的格式,往往會使得文字看起總是偏下,圖示總有一些偏上,現在你知道鍋應該甩給文字了。這個時候就要請我們的vertical-align數值屬性來精確的調整文字的位置了。在不知道數值怎麼設定的情況下,不如先來看看vertical-align:0,會發生什麼,同時為了便於觀察,把圖片的垂直居中也改為基於基線對齊。

<div style="line-height:150px;position: relative;">
	<span style="vertical-align: 0;font-size: 50px">我的vertical-align是0,x</span>
	<img src="../小和尚.jpg" style="vertical-align: baseline;width: 50px;height: 50px">
</div>

  這時候可以看到,vertical-align:0的表現和vertical-align:baseline的表現一模一樣!因此,vertical-align:數值,是基於baseline對齊的,為了圖片和文字最終能居中,我們當然先要保證圖片先居中(因為圖片替換屬性的特性的總能保持完全居中),再去調整文字的數值。最終調整結果如下

<div style="line-height:150px;position: relative;">
	<span style="vertical-align: -10px;font-size: 50px">藉助x輔助調整數值,x</span>
	<img src="../小和尚.jpg" style="vertical-align: middle;width: 50px;height: 50px">
</div>

 

  除了數值,vertical-align還支援基於line-height的百分比計算數值,個人覺得沒什麼用就不說明了。

7.baseline在inline-block元素中的詭異表現

  又到了CSS靈異事件的部分了,我覺得這些個靈異事件甚至可以單獨抽出一個章節來講。vertical-align屬性的預設值baseline在文字之類的內聯元素那裡是指x的下邊緣,對於替換元素則是替換元素的下邊緣,看完這章應該對這兩句話有很深的印象了,但是,如果是inline-block元素,規則就要複雜一些了。

  一個inline-block元素,如果裡面沒有內聯元素(包括匿名內聯元素),且overflow不是visible,則該元素的基線是其margin盒子的底邊緣,否則,其基線就是其元素裡面最後一行內聯元素的基線。

  上面的概念全部標紅,因為inline-block元素在實際開發中非常重要,搞清楚inline-block的詭異CSS是十分有必要的,理論看起太乾,不如來個實際例子看看到底是怎麼回事。

<div>
	<span style="margin-bottom: 10px"></span>
	<span>我有自己的內x</span>
</div>
<style>
	div{
		background: rgba(0,0,0,0.1);
	}
	span{
		background: rgba(0,0,0,0.5);
		display: inline-block;
		width: 100px;
		height: 100px;
	}
</style>

   

  可以看到第一個inline-block元素由於沒有內容導致其baseline位置發生改變,變成了margin盒子的下邊緣,而另一個inline-block元素的基線是其最後一個行框盒子的基線,在本例中,就是第二行的x字母,由於inline元素的佈局是基於baseline的,因此就出現瞭如圖所示的"錯位"。

  除了空inline-block元素和非空inline-block元素會發生錯位,行數不同的inline-block元素也會發生錯位。

  雖然這兩種情況都會發生錯位,但需要注意他們發生錯位的機制完全不同!

  想要解決這個錯位問題其實很簡單,只要你明白錯位問題的產生的根本原因是inline-block元素和baseline有過節即可,所以inline-block元素的vertical-align可以用不基於基線的屬性,由於數值屬性也是基於基線的因此也會發生錯位問題,所以需要具體問題具體分析,我只給出一種最簡單的解決方案。如下所示