一、當line-height與vertical-align相遇,會發生很多匪夷所思的現象
首先,請看如下代碼:

1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title></title> 6 <style> 7 div { 8 background-color: red; 9 line-height: normal; 10 } 11 </style> 12 </head> 13 <body> 14 <div> 15 <img src="http://a.hiphotos.baidu.com/zhidao/pic/item/72f082025aafa40fa38bfc55a964034f79f019ec.jpg" 16 alt="A picture" style="width:175px;height:100px" /> 17 </div> 18 </body> 19 </html>
其效果圖是這樣的:
可以看到,圖像的下邊緣依然有一些背景顏色,極其影響頁面的美觀,那么,這些紅色背景是怎么來的呢?
如果我們改變line-height的值,會發現圖像下邊緣的紅色背景區域也會跟着變化,比如將line-height值從normal改為50px,其效果圖為:
那么,是什么原因導致了這一變化呢?
為了說明得更清楚,我們向頁面中添加另外一些輔助性的東西(一些文本);代碼如下:

1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title>隱藏文本節點分析</title> 6 <style> 7 div { 8 font-size: 16px; 9 background-color: red; 10 line-height:50px; 11 } 12 13 span { 14 display: inline-block; 15 background-color: green; 16 } 17 </style> 18 </head> 19 <body> 20 <div> 21 <img src="http://a.hiphotos.baidu.com/zhidao/pic/item/72f082025aafa40fa38bfc55a964034f79f019ec.jpg" 22 alt="A picture" style="width:175px;height:100px" /> 23 <span>Something xxx</span> 24 </div> 25 </body> 26 </html>
其頁面效果為:
如果我們改變字體大小,比如將font-size值從16px改為32px;其頁面效果為:
如果我們將font-size的值改成80px,效果會更明顯,像這樣:
我們知道,line-height決定了行內元素的高度,所以在我們只改變font-size而沒有改變line-height的情況下,綠色背景的文本高度並沒有任何變化。
在vertical-align的默認值為baseline的情況下,圖像的下邊緣始終與文本的基線對齊。
由於font-size增加了,所以內容區的高度增加了,在行內框高度不變的前提下,只能行間距減小,於是整個行內框都表現得向上移動。
然后我們刪掉輔助的<span>元素,保留所有CSS設置,會發現圖像紋絲不動,如下圖:
也就是說,在圖像右邊有文本的時候,圖像與其基線對齊;即使圖像右邊沒有文本,圖像也與一個假想的文本的基線對齊;由此,引出了一個“隱藏文本節點”的概念。
(注:此概念來自張鑫旭大神,如需了解原作者的觀點,請移步他的個人博客,本文觀點只代表我個人理解。)
vertical-align:baseline,要求一個元素的基線與其父元素的基線對齊;
如果一個元素沒有基線,比如圖像或者表單輸入元素或者其它替換元素,則是元素的底端與父元素的基線對齊。
然而,如果父元素是一個空的div,如何確定父元素的基線?
這時,我們就可以假設,其實父元素中有一個隱藏的文本節點,只是我們看不見,它在暗中確定了父元素的基線。
這就是我對於“隱藏文本節點”的理解。
通過前面的分析,可以得知,圖像下邊緣多出來的一部分紅色背景區域,實際上是隱藏文本節點在作怪;
更准確地說,是因為隱藏文本節點的line-height以及vertical-align:baseline在作怪。
知道了原因,我們就能對症下葯地解決問題,以下是三種去除那些紅色背景的方法。
方法一:由於vertical-align只能作用於行內元素和替換元素(如圖像和表單輸入元素),只要將圖像塊狀化,就能解決問題。代碼如下:
1 img {
2 display:block; 3 }
方法二:由於vertical-align的默認值為baseline,圖像的下邊緣與那些隱藏文本的基線對齊,才會多出來一些紅色背景;如果改變vertical-align的值,將其設置為bottom(底線對齊),就能解決問題。代碼如下:
1 img {
2 vertical-align: bottom; 3 }
方法三:設置line-height的值足夠小。代碼如下:
1 div {
2 line-height: 0; 3 }
我對方法三的理解:
只要一個文本存在,它就會有四條線,頂線、中線、基線、底線,而基線是根基所在,其他三條線都是根據基線定義的,所以改變字體大小,基線是不會變化的,其他三條線會相應調整位置。即使font-size為0,文本根本看不見了,但是要記得,字體大小與行內框高度沒有半毛錢關系。
影響行框的只有行內框。
這里的圖像行內框高度就是它自身的height,文本的行內框高度為行高,這一行的行框是包含了圖像行內框的頂端與文本行內框的底端形成的。
因為圖像的底端與文本的基線對齊,只要文本的行內框底端低於文本的基線,那么,圖像的下邊緣就總會有空隙。
當我們改變line-height,實際上就是在改變隱藏文本節點的行內框,line-height越小,它的行內框越小,當line-height等於某一數值時,文本行內框的底端與基線持平,繼續減小line-height,行內框的底端在基線之上,直至line-height減小到0,行內框高度為0;但是即使line-height為0,文本是不會動的,文本還是文本,它的基線會始終與圖像的“基線”對齊。
所以最簡單的方法就是設置line-height為0,當一個文本元素的行內框高度為0,在構造行框的時候就只會考慮圖像的行內框,圖像的下邊緣自然沒有多余的空隙。
上面三種方法的頁面效果一致,實踐中可根據需要使用。
二、沒有最怪,只有更怪
先上重點:
inline-block的基線是正常流中最后一個line box的基線,除非,這個line box里面既沒有line boxes ,或者其本身overflow屬性的計算值不是visible,則它的基線是margin底邊緣。
上面這段不是人話,看不懂沒關系,下面是人話:
如果一個inline-block元素里面是空的,或者它本身有overflow屬性,這種情況下基線是它margin的底邊緣。
如果一個inline-block元素里面不是空的(比如里面有文字或者圖像),則它的基線由正常流中最后一個line box的基線決定。
舉個例子,請看下面代碼:

1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title></title> 6 <style> 7 .box { 8 display:inline-block; 9 width:200px; 10 height:150px; 11 border:2px solid red; 12 font-size: 16px; 13 } 14 15 p { 16 background-color: orange; 17 margin:0; 18 } 19 </style> 20 </head> 21 <body> 22 <div class="box"></div> 23 <div class="box"> 24 <p>I am the first line.</p> 25 <p>I am the second line.</p> 26 </div> 27 </body> 28 </html>
頁面效果:
這是神馬情況?
第一個盒子,里面是空的,所以它的基線是它的下邊框。
(基線本來應該是margin的底邊緣,此處為便於展示,margin為默認0,所以下邊框就是它的基線;有興趣的朋友可自己設置margin的大小看看效果。設置了margin之后,頁面效果會更怪,大家可以娛樂一下。)
第二個盒子,里面有文字,所以它的基線是正常流中最后一個行框的基線決定,也就是第二行的基線。
默認情況下基線對齊,所以它們就變成這樣啦。
(為便於分析,此處<p>元素的margin為0,並設置了背景顏色。)
再來玩個游戲,如果將文字的行高改變,會怎樣呢?
當行高為0:
由於line-height決定了行內框的高度,從而依次絕對了行框、包含框的高度;在依次減小line-height的時候,背景顏色區域的高度相應減小;
當line-height為0時,行內框的高度為0,兩個<p>元素高度都是0,它們雖然都在div這個盒子里面,但是它們不占任何空間。
前文有提到,內容區的中點將行高上下均分,當line-height為0,文字沒有高度,內容區的上下部分都是0,盒子不需要在邊框內部給文字留空間,所以從它內容區的中點穿過。
三、Note:
對於行內元素,vertical-align和line-height雖然不可見,但實際上【到處都是】!
也就是說,只要是行內元素,一定會受它們影響。
在遇到由vertical-align:baseline和line-height組合造成的各種無法理解的怪異現象,可以直接放大招,要么行高改為0,要么廢掉基線對齊(比如底線對齊、頂線對齊就很好啊),要么兩個一起改。
四、vertical-align的其他可選值
1. top,元素行內框的頂端與包含該元素的行框的頂端對齊。
2. bottom,元素行內框的底端與包含該元素的行框的底端對齊。
3. middle,元素行內框的垂直中點與父元素基線上方0.5個x(相對於父元素的字體大小)的距離處的一個點對齊;簡單地說就是與x的中心點對齊。
4. text-top,元素行內框的頂端與父元素內容區的頂端對齊。
5. text-bottom,元素行內框的底端與父元素內容區的底端對齊。
6. super,將元素的內容區和行內框上移,距離未指定。
7. sub,將元素的內容區和行內框下移,距離未指定。
(注意:vertical-align的super和sub值只是單純地上下移動元素行內框,並不改變字體大小,與<sup>和<sub>標簽不同。)
8. 百分數,以行高的數值為基准計算。
9. 數字,這個好理解,不解釋。
五、如果各個行內元素的vertical-align屬性值各不相同,該如何處理?

1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title>vertical-align混雜的情況</title> 6 <style> 7 div { 8 font-size: 16px; 9 background-color: red; 10 margin-top:100px; 11 } 12 13 .model { 14 display: inline-block; 15 font-size: 32px; 16 line-height: 32px; 17 background-color: #000; 18 color: white; 19 } 20 21 img { 22 border:2px solid #000; 23 margin-left: 20px; 24 } 25 26 .p1,.p2,.p3,.p4 { 27 display: inline-block; 28 } 29 30 .p1 { 31 vertical-align: top; 32 height: 90px; 33 width:120px; 34 } 35 36 .p2 { 37 vertical-align: text-top; 38 height: 150px; 39 width: 200px; 40 } 41 42 .p3 { 43 vertical-align: bottom; 44 height: 210px; 45 width: 350; 46 } 47 48 .p4 { 49 vertical-align: text-bottom; 50 height: 270px; 51 width: 450px; 52 } 53 54 55 </style> 56 </head> 57 <body> 58 <div class="box1"> 59 <img class="p1" src="http://pic1.win4000.com/wallpaper/c/537b28b60619b.jpg" alt="A picture" /> 60 <span class="model">x</span> 61 </div> 62 <p>上圖,x是這個div里面的原住民,它是一個隱藏文本節點,本來我們看不見,這里只是便於分析,所以將它顯示出來。</p> 63 <p>本來x小朋友在里面無憂無慮地玩耍,某一天,來了一個圖像1,要和它玩對齊游戲,游戲規則,top對齊,於是,圖像1的行內框頂端與x的行內框頂端對齊,形成一個行框,如上圖。</p> 64 <div class="box2"> 65 <img class="p1" src="http://pic1.win4000.com/wallpaper/c/537b28b60619b.jpg" alt="A picture" /> 66 <span class="model">x</span> 67 <img class="p2" src="http://pic1.win4000.com/wallpaper/c/537b28b60619b.jpg" alt="A picture" /> 68 <span class="model">x</span> 69 </div> 70 <p>接上回。。。</p> 71 <p>現在行框已經形成啦,來了一個圖像2,也要玩對其游戲,游戲規則,text-top對齊,本來應該是圖像2的行內框頂端與父元素的內容區的頂端對齊,但是父元素里面沒有文本哪兒來的內容區呢,於是,拿x這個隱藏家伙來代替,與x的內容區的頂端對齊,如上圖。</p> 72 <div class="box3"> 73 <img class="p1" src="http://pic1.win4000.com/wallpaper/c/537b28b60619b.jpg" alt="A picture" /> 74 <img class="p2" src="http://pic1.win4000.com/wallpaper/c/537b28b60619b.jpg" alt="A picture" /> 75 <span class="model">x</span> 76 <img class="p3" src="http://pic1.win4000.com/wallpaper/c/537b28b60619b.jpg" alt="A picture" /> 77 </div> 78 <p>接上回。。。</p> 79 <p>某一天,來了一個圖像3,它要bottom對齊。</p> 80 <p>這個簡單啊,bottom對齊要求圖像的行內框底端與行框的底端對齊,如今大大的行框就在那里,直接把圖像3放上去就好了。</p> 81 <p>但是這個圖像3有點太高了,把行框都撐高了,沒關系,行框會自動調整高度,形成新的行框。</p> 82 <p>但是新的行框形成之后,圖像1本來是要與行框的頂端對齊的,現在也只能跟着行框往上走了。</p> 83 <div class="box4"> 84 <img class="p1" src="http://pic1.win4000.com/wallpaper/c/537b28b60619b.jpg" alt="A picture" /> 85 <img class="p2" src="http://pic1.win4000.com/wallpaper/c/537b28b60619b.jpg" alt="A picture" /> 86 <span class="model">x</span> 87 <img class="p3" src="http://pic1.win4000.com/wallpaper/c/537b28b60619b.jpg" alt="A picture" /> 88 <img class="p4" src="http://pic1.win4000.com/wallpaper/c/537b28b60619b.jpg" alt="A picture" /> 89 <span class="model">x</span> 90 </div> 91 <p>接上回。。。</p> 92 <p>又有一天,來了一個圖像4,這次它要text-bottom對齊,怎么辦呢?</p> 93 <p>text-bottom對齊,就是要把圖像4的行內框的底端與父元素的內容區的底端對齊,可是。。。唉,又只有拿x來代替啦,還好,x一直在原地沒動呢,隨時都能找到。</p> 94 <p>現在,圖像4的行內框底端與x的內容區底端對齊。對齊之后發現,我勒個去,這個圖像4怎么那么高啊。</p> 95 <p>沒關系,行框很靈活,自動調整高度,絕對會把它裝進去。</p> 96 <p>哎呀,行框又變高了,圖像1,你得跟上啊,你是要跟行框頂端對齊的說。</p> 97 </body> 98 </html>
我對於vertical-align各種對齊方式的總結:
首先,在一個空行中,存在一個隱藏文本節點,看不見摸不着,但卻以某種方式存在着,因為繼承而來的font-size和line-height,它有自己的內容區和行內框。
然后,這個空行來了第一個行內元素,這個行內元素的行內框會與隱藏文本節點的行內框以指定或默認的方式對齊,從而形成一個最初的行框。
之后,行內元素一個一個地進入這一行,一個一個地按照指定或默認的方式,分別與已經形成的行框對齊,或者分別與父元素的內容區對齊。
記住,任何一個行內元素的對齊方式都是獨立的,與其它行內元素沒有任何關系。