首先我們要明確 line-height 的定義,line-height指的是兩條文字基線之間的距離。
行內框盒子模型
所有內聯元素的樣式表現都與行內框盒子模型有關。所以這個概念是非常重要的。
<p>這是一段文字,這里有個<em>em</em> 標簽。</p>
如上面一段普普通通的代碼,卻包含了4種盒子:
1)“內容區域”(content area),是一種圍繞文字看不見的盒子,可理解為選中文字藍色背景區域,如下圖。“內容區域”的大小與 font-size 大小相關;
2)“內聯盒子”(inline-boxes),“內聯盒子”不會讓內容成塊顯示,而是排成一行。如果文字外部含 inline 水平的標簽(如span,a,em等),則屬於“內聯盒子”,如下圖紫框處。如果是光禿禿的文字,則屬於“匿名內聯盒子”,如下圖紅框處;
3)“行框盒子”(line boxes),每一行就是一個“行框盒子”,每個“行框盒子”又是由一個一個“內聯盒子”組成,“行框盒子”如下圖紅框處;
4)<p> 標簽所在的“包含盒子”(containing box),如下圖紅框處。此盒子由一行一行的“行框盒子”組成
line-height 的高度機理
疑問一:元素高度是從何而來的呢?是由里面的文字撐開的嗎?
答案:不是的,並不是由文字撐開的,實際上是由 line-height 決定的。
這時可能會提出疑問:line-height明明是兩基線距離,單行文字哪來的行高呢?
關於這個問題,我們需要了解的是:
1)行高由於其繼承性,影響無處不在,即使單行文本也不例外。
2)行高只是幕后黑手,高度的表現不是行高,而是內容區域和行間距。
而 內容區域 + 行間距 = 行高,正好高度表現等於行高,給人感覺上是行高起了作用。
1. 內容區域高度只與字號以及字體有關,與 line-height 沒有任何關系。
2. 在simsun(宋體)字體下,內容區域高度等於文字大小值。
因此,在 simsun(宋體)字體下:
font-size + 行間距 = line-height
那行間距的就可以這樣計算了:
font-size: 240px; line-height: 360px; 則行間距 = 360px - 240px = 120px;
行間距上下拆分,就有了“半行間距”。
半行間距 = (行高 - 內容區域高度)/2
總結:
行高決定內聯盒子高度,但高度表現是由行間距和內容區域表現的;行間距牆頭草,可大可小(甚至負值),它的作用就是保證內聯盒子高度正好等於行高。
疑問二:如果行框盒子里面有多個不同行高的內聯盒子,這時高度會如何表現呢?是由行高最高的內聯盒子決定的嗎?
答案:不對。這個問題比較復雜,下回再解。
我們還要知道,多行文本的高度就是單行文本高度累加。
疑問三:如果行框盒子里面混入inline-block水平元素(如圖片),高度如何表現呢?
解釋在最后一部分。
line-height 各類屬性值
- normal 默認屬性值,不同瀏覽器表現不同,且與元素字體關聯。
- <number> 使用數值作為行高值,根據當前元素的font-size大小計算
- <length> 使用具體長度值作為行高值
- <percent> 使用百分比值作為行高值,相當於設置了該line-height屬性的元素的font-size大小來計算
- inherit 行高繼承。如input框等元素默認行高是normal,使用inherit可以讓文本樣式可控性更強。
應用元素有差別:
line-height:1.5 所有可繼承元素根據自己的 font-size 重新計算行高。推薦使用
line-height:150%/1.5em 當前元素根據font-size計算行高,直接繼承給下面的元素。
body全局數值行高使用經驗
body{ font-size: 14px; line-height: ? }
匹配20像素的使用經驗——方便心算
line-height = 20px / 14px ≈ 1.4286
body{ font-size: 14px; line-height: 1.4286; }
line-height與圖片表現
行高會不會影響圖片實際占據的高度?
答案:不會。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <style> p{ background-color: #ccc; } span{ background-color: white; } </style> </head> <body> <section> <p> <img src="./123.jpg" /><span>xxxxxxx</span> </p> </section> </body> </html>
效果如下圖,圖片會與右邊的文字基線對齊。
當我們把span高度改一下,可以看到為了與文字基線對齊,p的高度變高了。
span{ display: inline-block; height: 50px; background-color: white; }
由上可知,行高改變容器的高度只是 vertical-align 和文字行高變化共同起的作用,圖片占據的高度還是它原本的高度。
下面我們再來看,
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <style> p{ background-color: #ccc; } </style> </head> <body> <section> <p> <img src="./123.jpg" /> </p> </section> </body> </html>
效果如下圖,右邊沒有文字了,但下面還是會有一點空隙。
原因是:
對於一個block元素,就像有一個文本節點在里面一樣,看不到,獲取不到,稱之為隱匿文本節點。內聯塊級元素img默認對齊方式是基線baseline,要與文本對齊,文本存在line-height,所以存在間隙。
那么如何消除圖片底部的間隙呢?
方法1:圖片塊狀化 ——無基線對齊
img{
display: block;
}
方法二:圖片底線對齊
img{ vertical-align: bottom; }
方法三:行高足夠小——基線上移
p{ background-color: #ccc; line-height: 0; }
方法四:消除隱匿文本字體大小
p{ background-color: #ccc; font-size: 0; }
小圖片和大文字
基本上高度受行高控制。
line-height 的實際應用
圖片水平垂直居中
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <style> p{ background-color: #ccc; line-height: 300px; text-align: center; } img{ vertical-align: middle; } </style> </head> <body> <section> <p> <img src="./123.jpg" /> </p> </section> </body> </html>
效果如下:
多行文本水平垂直居中
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <style> p{ line-height: 250px; text-align: center; background-color: #ccc; } span{ display: inline-block; line-height: normal; text-align: left; vertical-align: middle; } </style> </head> <body> <section> <p> <span> 多行文本水平垂直居中實現的原理和圖片的實現是一樣的,區別在於要把 多行文本所在容器的 display 轉換為和圖片一樣的 inline-block,以及 重置外部繼承的 text-align 和 line-height 屬性值。 </span> </p> </section> </body> </html>
效果如下: